diff --git a/packages/react-scripts/config/env.js b/packages/react-scripts/config/env.js
index c018467a95b..0097f3cf304 100644
--- a/packages/react-scripts/config/env.js
+++ b/packages/react-scripts/config/env.js
@@ -10,6 +10,36 @@
 // @remove-on-eject-end
 'use strict';
 
+var fs = require('fs');
+var paths = require('./paths');
+
+var NODE_ENV = process.env.NODE_ENV;
+if (!NODE_ENV) {
+  throw new Error(
+    'The NODE_ENV environment variable is required but was not specified.'
+  );
+}
+
+// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
+var dotenvFiles = [
+  paths.dotenv + '.' + NODE_ENV + '.local',
+  paths.dotenv + '.' + NODE_ENV,
+  paths.dotenv + '.local',
+  paths.dotenv,
+];
+// Load environment variables from .env* files. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set.
+// https://github.com/motdotla/dotenv
+dotenvFiles.forEach(dotenvFile => {
+  if (fs.existsSync(dotenvFile)) {
+    require('dotenv').config({
+      silent: true,
+      path: dotenvFile,
+    });
+  }
+});
+
 // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
 // injected into the application via DefinePlugin in Webpack configuration.
 const REACT_APP = /^REACT_APP_/i;
diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js
index 76397756040..915b1a83865 100644
--- a/packages/react-scripts/config/paths.js
+++ b/packages/react-scripts/config/paths.js
@@ -74,6 +74,7 @@ function getServedPath(appPackageJson) {
 
 // config after eject: we're in ./config/
 module.exports = {
+  dotenv: resolveApp('.env'),
   appBuild: resolveApp('build'),
   appPublic: resolveApp('public'),
   appHtml: resolveApp('public/index.html'),
@@ -95,6 +96,7 @@ function resolveOwn(relativePath) {
 
 // config before eject: we're in ./node_modules/react-scripts/config/
 module.exports = {
+  dotenv: resolveApp('.env'),
   appPath: resolveApp('.'),
   appBuild: resolveApp('build'),
   appPublic: resolveApp('public'),
@@ -124,6 +126,7 @@ if (
   __dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1
 ) {
   module.exports = {
+    dotenv: resolveOwn('template/.env'),
     appPath: resolveApp('.'),
     appBuild: resolveOwn('../../build'),
     appPublic: resolveOwn('template/public'),
diff --git a/packages/react-scripts/fixtures/kitchensink/.env b/packages/react-scripts/fixtures/kitchensink/.env
index 3e6e8a5a360..3e2f7b14a73 100644
--- a/packages/react-scripts/fixtures/kitchensink/.env
+++ b/packages/react-scripts/fixtures/kitchensink/.env
@@ -1 +1,3 @@
-REACT_APP_FILE_ENV_MESSAGE=fromtheenvfile
+REACT_APP_X = x-from-original-env
+REACT_APP_ORIGINAL_1 = from-original-env-1
+REACT_APP_ORIGINAL_2 = from-original-env-2
diff --git a/packages/react-scripts/fixtures/kitchensink/.env.development b/packages/react-scripts/fixtures/kitchensink/.env.development
new file mode 100644
index 00000000000..cc10be5e6d8
--- /dev/null
+++ b/packages/react-scripts/fixtures/kitchensink/.env.development
@@ -0,0 +1,2 @@
+REACT_APP_X = x-from-development-env
+REACT_APP_DEVELOPMENT = development
diff --git a/packages/react-scripts/fixtures/kitchensink/.env.local b/packages/react-scripts/fixtures/kitchensink/.env.local
new file mode 100644
index 00000000000..b248646bdad
--- /dev/null
+++ b/packages/react-scripts/fixtures/kitchensink/.env.local
@@ -0,0 +1,2 @@
+REACT_APP_X = x-from-original-local-env
+REACT_APP_ORIGINAL_2 = override-from-original-local-env-2
diff --git a/packages/react-scripts/fixtures/kitchensink/.env.production b/packages/react-scripts/fixtures/kitchensink/.env.production
new file mode 100644
index 00000000000..ec8bdcb54f3
--- /dev/null
+++ b/packages/react-scripts/fixtures/kitchensink/.env.production
@@ -0,0 +1,2 @@
+REACT_APP_X = x-from-production-env
+REACT_APP_PRODUCTION = production
diff --git a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js
index b90d12ab12e..89d19fcf4b1 100644
--- a/packages/react-scripts/fixtures/kitchensink/integration/env.test.js
+++ b/packages/react-scripts/fixtures/kitchensink/integration/env.test.js
@@ -16,8 +16,27 @@ describe('Integration', () => {
       const doc = await initDOM('file-env-variables');
 
       expect(
-        doc.getElementById('feature-file-env-variables').textContent
-      ).to.equal('fromtheenvfile.');
+        doc.getElementById('feature-file-env-original-1').textContent
+      ).to.equal('from-original-env-1');
+      expect(
+        doc.getElementById('feature-file-env-original-2').textContent
+      ).to.equal('override-from-original-local-env-2');
+
+      if (process.env.NODE_ENV === 'production') {
+        expect(doc.getElementById('feature-file-env').textContent).to.equal(
+          'production'
+        );
+        expect(doc.getElementById('feature-file-env-x').textContent).to.equal(
+          'x-from-production-env'
+        );
+      } else {
+        expect(doc.getElementById('feature-file-env').textContent).to.equal(
+          'development'
+        );
+        expect(doc.getElementById('feature-file-env-x').textContent).to.equal(
+          'x-from-development-env'
+        );
+      }
     });
 
     it('NODE_PATH', async () => {
diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/env/FileEnvVariables.js b/packages/react-scripts/fixtures/kitchensink/src/features/env/FileEnvVariables.js
index a8a1e98fe71..55ae368e437 100644
--- a/packages/react-scripts/fixtures/kitchensink/src/features/env/FileEnvVariables.js
+++ b/packages/react-scripts/fixtures/kitchensink/src/features/env/FileEnvVariables.js
@@ -10,7 +10,16 @@
 import React from 'react';
 
 export default () => (
-  <span id="feature-file-env-variables">
-    {process.env.REACT_APP_FILE_ENV_MESSAGE}.
+  <span>
+    <span id="feature-file-env-original-1">
+      {process.env.REACT_APP_ORIGINAL_1}
+    </span>
+    <span id="feature-file-env-original-2">
+      {process.env.REACT_APP_ORIGINAL_2}
+    </span>
+    <span id="feature-file-env">
+      {process.env.REACT_APP_DEVELOPMENT}{process.env.REACT_APP_PRODUCTION}
+    </span>
+    <span id="feature-file-env-x">{process.env.REACT_APP_X}</span>
   </span>
 );
diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js
index fe4ec959d4d..da9004f9ee6 100644
--- a/packages/react-scripts/scripts/build.js
+++ b/packages/react-scripts/scripts/build.js
@@ -20,11 +20,8 @@ process.on('unhandledRejection', err => {
   throw err;
 });
 
-// Load environment variables from .env file. Suppress warnings using silent
-// if this file is missing. dotenv will never modify any environment variables
-// that have already been set.
-// https://github.com/motdotla/dotenv
-require('dotenv').config({ silent: true });
+// Ensure environment variables are read.
+require('../config/env');
 
 const chalk = require('chalk');
 const fs = require('fs-extra');
diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js
index 12cce8ed313..b44fc44c907 100644
--- a/packages/react-scripts/scripts/start.js
+++ b/packages/react-scripts/scripts/start.js
@@ -19,11 +19,8 @@ process.on('unhandledRejection', err => {
 
 process.env.NODE_ENV = 'development';
 
-// Load environment variables from .env file. Suppress warnings using silent
-// if this file is missing. dotenv will never modify any environment variables
-// that have already been set.
-// https://github.com/motdotla/dotenv
-require('dotenv').config({ silent: true });
+// Ensure environment variables are read.
+require('../config/env');
 
 const fs = require('fs');
 const chalk = require('chalk');
diff --git a/packages/react-scripts/scripts/test.js b/packages/react-scripts/scripts/test.js
index 5c395999d97..ef333e6c004 100644
--- a/packages/react-scripts/scripts/test.js
+++ b/packages/react-scripts/scripts/test.js
@@ -20,11 +20,8 @@ process.on('unhandledRejection', err => {
   throw err;
 });
 
-// Load environment variables from .env file. Suppress warnings using silent
-// if this file is missing. dotenv will never modify any environment variables
-// that have already been set.
-// https://github.com/motdotla/dotenv
-require('dotenv').config({ silent: true });
+// Ensure environment variables are read.
+require('../config/env');
 
 const jest = require('jest');
 const argv = process.argv.slice(2);
diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md
index 933e9b0cdcb..cc66b9526bb 100644
--- a/packages/react-scripts/template/README.md
+++ b/packages/react-scripts/template/README.md
@@ -752,6 +752,24 @@ To define permanent environment variables, create a file called `.env` in the ro
 REACT_APP_SECRET_CODE=abcdef
 ```
 
+<!--
+TODO: uncomment (and tweak) the doc for 0.10
+What .env* files are used?
+
+* `.env` - Default
+* `.env.development`, `.env.test`, `.env.production` - Environment-specific settings.
+* `.env.local` - Local overrides. This file is loaded for all environments except test.
+* `.env.development.local`, `.env.test.local`, `.env.production.local` - Local overrides of environment-specific settings.
+
+Files priority (file is skipped if does not exist):
+
+* npm test - `.env.test.local`, `env.test`, `.env.local`, `.env`
+* npm run build - `.env.production.local`, `env.production`, `.env.local`, `.env`
+* npm start - `.env.development.local`, `env.development`, `.env.local`, `.env`
+
+Priority from left to right.
+-->
+
 These variables will act as the defaults if the machine does not explicitly set them.<br>
 Please refer to the [dotenv documentation](https://github.com/motdotla/dotenv) for more details.
 
diff --git a/packages/react-scripts/template/gitignore b/packages/react-scripts/template/gitignore
index 927d17bb9c5..d30f40ef442 100644
--- a/packages/react-scripts/template/gitignore
+++ b/packages/react-scripts/template/gitignore
@@ -11,8 +11,11 @@
 
 # misc
 .DS_Store
-.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
-