diff --git a/README.rst b/README.rst
index 06a22b0028c2eae6f587b98693e44f22e9e753b3..5998d133b0d64dfdb05df6f303ae1585d63b3a9a 100644
--- a/README.rst
+++ b/README.rst
@@ -25,6 +25,7 @@ Features
 - Bootstrap 3 and Font Awesome 4 with starter templates
 - Flask-SQLAlchemy with basic User model
 - Easy database migrations with Flask-Migrate
+- Configuration in environment variables, as per `The Twelve-Factor App <https://12factor.net/config>`_
 - Flask-WTForms with login and registration forms
 - Flask-Login for authentication
 - Flask-Bcrypt for password hashing
diff --git a/tasks.py b/tasks.py
index 7e412cec31e0aa87d6be37156fc4f29ca4e3c8be..9d8d5dfb52c92a8f0c4802abfed34f646fb45953 100644
--- a/tasks.py
+++ b/tasks.py
@@ -13,7 +13,6 @@ with open(os.path.join(HERE, 'cookiecutter.json'), 'r') as fp:
     COOKIECUTTER_SETTINGS = json.load(fp)
 # Match default value of app_name from cookiecutter.json
 COOKIE = os.path.join(HERE, COOKIECUTTER_SETTINGS['app_name'])
-AUTOAPP = os.path.join(COOKIE, 'autoapp.py')
 REQUIREMENTS = os.path.join(COOKIE, 'requirements', 'dev.txt')
 
 
@@ -42,7 +41,8 @@ def clean(ctx):
 
 
 def _run_flask_command(ctx, command):
-    ctx.run('FLASK_APP={0} flask {1}'.format(AUTOAPP, command), echo=True)
+    os.chdir(COOKIE)
+    ctx.run('flask {0}'.format(command), echo=True)
 
 
 @task(pre=[clean, build])
@@ -52,12 +52,14 @@ def test(ctx):
             echo=True)
     _run_npm_command(ctx, 'run lint')
     os.chdir(COOKIE)
+    shutil.copyfile(os.path.join(COOKIE, '.env.example'),
+                    os.path.join(COOKIE, '.env'))
     _run_flask_command(ctx, 'lint')
     _run_flask_command(ctx, 'test')
 
+
 @task
 def readme(ctx, browse=False):
-    ctx.run("rst2html.py README.rst > README.html")
+    ctx.run('rst2html.py README.rst > README.html')
     if browse:
         webbrowser.open_new_tab('README.html')
-
diff --git a/{{cookiecutter.app_name}}/.env.example b/{{cookiecutter.app_name}}/.env.example
new file mode 100644
index 0000000000000000000000000000000000000000..72367469b3b985bef77f520ffd4265033e820e5f
--- /dev/null
+++ b/{{cookiecutter.app_name}}/.env.example
@@ -0,0 +1,5 @@
+# Environment variable overrides for local development
+FLASK_APP=autoapp.py
+FLASK_ENV=development
+DATABASE_URL="sqlite:////tmp/dev.db"
+SECRET_KEY="not-so-secret"
diff --git a/{{cookiecutter.app_name}}/.gitignore b/{{cookiecutter.app_name}}/.gitignore
index be872525b75b9a0185aa7da3b41b5677d1ad07e4..24d2ea20b591eeb3960e56346b417c9ba781ffd4 100644
--- a/{{cookiecutter.app_name}}/.gitignore
+++ b/{{cookiecutter.app_name}}/.gitignore
@@ -51,3 +51,9 @@ env/
 # webpack-built files
 /{{cookiecutter.app_name}}/static/build/
 /{{cookiecutter.app_name}}/webpack/manifest.json
+
+# Configuration
+.env
+
+# Development database
+*.db
diff --git a/{{cookiecutter.app_name}}/Pipfile b/{{cookiecutter.app_name}}/Pipfile
index c195ac38741fd6844cc1a142af661b4bc5836e7c..d9b88d92d8f3f65ec1099acb350b4672689e8a37 100644
--- a/{{cookiecutter.app_name}}/Pipfile
+++ b/{{cookiecutter.app_name}}/Pipfile
@@ -40,6 +40,9 @@ Flask-Caching = ">=1.0.0"
 # Debug toolbar
 Flask-DebugToolbar = "==0.10.1"
 
+# Environment variable parsing
+environs = "==4.0.0"
+
 [dev-packages]
 # Testing
 pytest = "==3.6.1"
diff --git a/{{cookiecutter.app_name}}/README.rst b/{{cookiecutter.app_name}}/README.rst
index c39e4266c9b013bcfde3b9b515711028e1fc6826..0a895306ed8cdd28f15db936ccac42816b7bd420 100644
--- a/{{cookiecutter.app_name}}/README.rst
+++ b/{{cookiecutter.app_name}}/README.rst
@@ -8,13 +8,6 @@
 Quickstart
 ----------
 
-First, set your app's secret key as an environment variable. For example,
-add the following to ``.bashrc`` or ``.bash_profile``.
-
-.. code-block:: bash
-
-    export {{cookiecutter.app_name | upper}}_SECRET='something-really-secret'
-
 Run the following commands to bootstrap your environment ::
 
     git clone https://github.com/{{cookiecutter.github_username}}/{{cookiecutter.app_name}}
@@ -24,17 +17,12 @@ Run the following commands to bootstrap your environment ::
     {%- else %}
     pip install -r requirements/dev.txt
     {%- endif %}
+    cp .env.example .env
     npm install
     npm start  # run the webpack dev server and flask server using concurrently
 
 You will see a pretty welcome screen.
 
-In general, before running shell commands, set the ``FLASK_APP`` and
-``FLASK_DEBUG`` environment variables ::
-
-    export FLASK_APP=autoapp.py
-    export FLASK_DEBUG=1
-
 Once you have installed your DBMS, run the following to create your app's
 database tables and perform the initial migration ::
 
@@ -49,12 +37,14 @@ Deployment
 
 To deploy::
 
+    export FLASK_ENV=production
     export FLASK_DEBUG=0
+    export DATABASE_URL="<YOUR DATABASE URL>"
     npm run build   # build assets with webpack
     flask run       # start the flask server
 
 In your production environment, make sure the ``FLASK_DEBUG`` environment
-variable is unset or is set to ``0``, so that ``ProdConfig`` is used.
+variable is unset or is set to ``0``.
 
 
 Shell
diff --git a/{{cookiecutter.app_name}}/autoapp.py b/{{cookiecutter.app_name}}/autoapp.py
index f7ab4d671eae9a4902c12d6bf68fc10ab32f80ec..8bcd8c8fb43e8025537f0503a91d28bc484196df 100755
--- a/{{cookiecutter.app_name}}/autoapp.py
+++ b/{{cookiecutter.app_name}}/autoapp.py
@@ -1,10 +1,5 @@
 # -*- coding: utf-8 -*-
 """Create an application instance."""
-from flask.helpers import get_debug_flag
-
 from {{cookiecutter.app_name}}.app import create_app
-from {{cookiecutter.app_name}}.settings import DevConfig, ProdConfig
-
-CONFIG = DevConfig if get_debug_flag() else ProdConfig
 
-app = create_app(CONFIG)
+app = create_app()
diff --git a/{{cookiecutter.app_name}}/package.json b/{{cookiecutter.app_name}}/package.json
index 95a05b93d05350d1cbf543755dbf1137fff1e5d7..2e1b2e3c16352a59c75adccaca86400a1994eeed 100644
--- a/{{cookiecutter.app_name}}/package.json
+++ b/{{cookiecutter.app_name}}/package.json
@@ -6,7 +6,7 @@
     "build": "NODE_ENV=production webpack --progress --colors -p",
     "start": "concurrently -n \"WEBPACK,FLASK\" -c \"bgBlue.bold,bgMagenta.bold\" \"npm run webpack-dev-server\" \"npm run flask-server\"",
     "webpack-dev-server": "NODE_ENV=debug webpack-dev-server --port 2992 --hot --inline",
-    "flask-server": "FLASK_APP=$PWD/autoapp.py FLASK_DEBUG=1 flask run",
+    "flask-server": "flask run",
     "lint": "eslint \"assets/js/*.js\""
   },
   "repository": {
diff --git a/{{cookiecutter.app_name}}/requirements/prod.txt b/{{cookiecutter.app_name}}/requirements/prod.txt
index 41a67586e907c284a9925985d74d593a2df81088..bf4b3d7e132b5aa6d41b154e67ca41947ade9f10 100644
--- a/{{cookiecutter.app_name}}/requirements/prod.txt
+++ b/{{cookiecutter.app_name}}/requirements/prod.txt
@@ -35,3 +35,6 @@ Flask-Caching>=1.0.0
 
 # Debug toolbar
 Flask-DebugToolbar==0.10.1
+
+# Environment variable parsing
+environs==4.0.0
diff --git a/{{cookiecutter.app_name}}/tests/conftest.py b/{{cookiecutter.app_name}}/tests/conftest.py
index ab709ff4289902dfb95dc4f5bab91491e9363d4d..5bb60c0ebf5140c574b7497b0a203c849107302b 100644
--- a/{{cookiecutter.app_name}}/tests/conftest.py
+++ b/{{cookiecutter.app_name}}/tests/conftest.py
@@ -6,7 +6,6 @@ from webtest import TestApp
 
 from {{cookiecutter.app_name}}.app import create_app
 from {{cookiecutter.app_name}}.database import db as _db
-from {{cookiecutter.app_name}}.settings import TestConfig
 
 from .factories import UserFactory
 
@@ -14,7 +13,7 @@ from .factories import UserFactory
 @pytest.fixture
 def app():
     """An application for the tests."""
-    _app = create_app(TestConfig)
+    _app = create_app('tests.settings')
     ctx = _app.test_request_context()
     ctx.push()
 
diff --git a/{{cookiecutter.app_name}}/tests/settings.py b/{{cookiecutter.app_name}}/tests/settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..a13e1590daa3901caa4dee022dc7adc22f15773f
--- /dev/null
+++ b/{{cookiecutter.app_name}}/tests/settings.py
@@ -0,0 +1,11 @@
+"""Settings module for test app."""
+ENV = 'development'
+TESTING = True
+SQLALCHEMY_DATABASE_URI = 'sqlite://'
+SECRET_KEY = 'not-so-secret-in-tests'
+BCRYPT_LOG_ROUNDS = 4  # For faster tests; needs at least 4 to avoid "ValueError: Invalid rounds"
+DEBUG_TB_ENABLED = False
+CACHE_TYPE = 'simple'  # Can be "memcached", "redis", etc.
+SQLALCHEMY_TRACK_MODIFICATIONS = False
+WEBPACK_MANIFEST_PATH = 'webpack/manifest.json'
+WTF_CSRF_ENABLED = False  # Allows form testing
diff --git a/{{cookiecutter.app_name}}/tests/test_config.py b/{{cookiecutter.app_name}}/tests/test_config.py
deleted file mode 100644
index 755bed733dc8a982a640c55d86f13d2b926a56bd..0000000000000000000000000000000000000000
--- a/{{cookiecutter.app_name}}/tests/test_config.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Test configs."""
-from {{cookiecutter.app_name}}.app import create_app
-from {{cookiecutter.app_name}}.settings import DevConfig, ProdConfig
-
-
-def test_production_config():
-    """Production config."""
-    app = create_app(ProdConfig)
-    assert app.config['ENV'] == 'prod'
-    assert app.config['DEBUG'] is False
-    assert app.config['DEBUG_TB_ENABLED'] is False
-
-
-def test_dev_config():
-    """Development config."""
-    app = create_app(DevConfig)
-    assert app.config['ENV'] == 'dev'
-    assert app.config['DEBUG'] is True
diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py
index 4740288f2f586e8c1a632338cbd08f2fdd2ed987..08796457f5c845369224c0d07a70c6dacce9a480 100644
--- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py
+++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py
@@ -4,10 +4,9 @@ from flask import Flask, render_template
 
 from {{cookiecutter.app_name}} import commands, public, user
 from {{cookiecutter.app_name}}.extensions import bcrypt, cache, csrf_protect, db, debug_toolbar, login_manager, migrate, webpack
-from {{cookiecutter.app_name}}.settings import ProdConfig
 
 
-def create_app(config_object=ProdConfig):
+def create_app(config_object='{{cookiecutter.app_name}}.settings'):
     """An application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/.
 
     :param config_object: The configuration object to use.
diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py
index 2bf866e9f733b0e892f7330826f97f383e696882..4c920b089e5b2b541945d61c28506bb1c86a42f5 100644
--- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py
+++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py
@@ -1,49 +1,23 @@
 # -*- coding: utf-8 -*-
-"""Application configuration."""
-import os
-
-
-class Config(object):
-    """Base configuration."""
-
-    SECRET_KEY = os.environ.get('{{cookiecutter.app_name | upper}}_SECRET', 'secret-key')  # TODO: Change me
-    APP_DIR = os.path.abspath(os.path.dirname(__file__))  # This directory
-    PROJECT_ROOT = os.path.abspath(os.path.join(APP_DIR, os.pardir))
-    BCRYPT_LOG_ROUNDS = 13
-    DEBUG_TB_ENABLED = False  # Disable Debug toolbar
-    DEBUG_TB_INTERCEPT_REDIRECTS = False
-    CACHE_TYPE = 'simple'  # Can be "memcached", "redis", etc.
-    SQLALCHEMY_TRACK_MODIFICATIONS = False
-    WEBPACK_MANIFEST_PATH = 'webpack/manifest.json'
-
-
-class ProdConfig(Config):
-    """Production configuration."""
-
-    ENV = 'prod'
-    DEBUG = False
-    SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/example'  # TODO: Change me
-    DEBUG_TB_ENABLED = False  # Disable Debug toolbar
-
-
-class DevConfig(Config):
-    """Development configuration."""
-
-    ENV = 'dev'
-    DEBUG = True
-    DB_NAME = 'dev.db'
-    # Put the db file in project root
-    DB_PATH = os.path.join(Config.PROJECT_ROOT, DB_NAME)
-    SQLALCHEMY_DATABASE_URI = 'sqlite:///{0}'.format(DB_PATH)
-    DEBUG_TB_ENABLED = True
-    CACHE_TYPE = 'simple'  # Can be "memcached", "redis", etc.
-
-
-class TestConfig(Config):
-    """Test configuration."""
-
-    TESTING = True
-    DEBUG = True
-    SQLALCHEMY_DATABASE_URI = 'sqlite://'
-    BCRYPT_LOG_ROUNDS = 4  # For faster tests; needs at least 4 to avoid "ValueError: Invalid rounds"
-    WTF_CSRF_ENABLED = False  # Allows form testing
+"""Application configuration.
+
+Most configuration is set via environment variables.
+
+For local development, use a .env file to set
+environment variables.
+"""
+from environs import Env
+
+env = Env()
+env.read_env()
+
+ENV = env.str('FLASK_ENV', default='production')
+DEBUG = ENV == 'development'
+SQLALCHEMY_DATABASE_URI = env.str('DATABASE_URL')
+SECRET_KEY = env.str('SECRET_KEY')
+BCRYPT_LOG_ROUNDS = env.int('BCRYPT_LOG_ROUNDS', default=13)
+DEBUG_TB_ENABLED = DEBUG
+DEBUG_TB_INTERCEPT_REDIRECTS = False
+CACHE_TYPE = 'simple'  # Can be "memcached", "redis", etc.
+SQLALCHEMY_TRACK_MODIFICATIONS = False
+WEBPACK_MANIFEST_PATH = 'webpack/manifest.json'