Skip to content

Send a .env back

$ grim env:push --restart

You pulled a server's .env, changed a handful of values in your editor, and now the server has to get them. grim env:push is the second half of that round trip: it takes .env.<environment> from the project directory and puts it where the deployed app reads its .env.

Reach for it when several values change together, or when a line has to go away. For one value, grim env:set is shorter and never leaves a copy of production credentials on your disk. The first half is grim env:pull.

Usage

$ grim env:push                      # .env.production, asks before it overwrites
$ grim env:push --restart            # the same, then the app picks the values up
$ grim env:push staging --restart    # .env.staging to the staging server
$ grim env:push --force --restart    # no question, for scripts

Run it from the project directory, where both grim.json and the .env.<environment> file are. With no argument the environment is production.

Arguments and options

Push .env to remote server

Usage

grim env:push [--force] [--restart] [--] [<environment>]

Arguments

Argument Description
environment Target environment (optional, default: production)

Options

Option Description
--force Skip confirmation prompt
--restart Restart app and clear config cache after push

What it actually does

  1. Looks for the local file. .env.<environment> in the project directory. The argument picks the file and the server at once, so staging can never upload .env.production.
  2. Finds the server. The same way grim env:pull does: deploy.environments.<environment> in grim.json, then deploy itself, then your registration in ~/.grim/servers.json. The path falls back to /opt/<project>, or /opt/<project>-<environment> for anything but production: the directory grim server:add-project makes. A top-level deploy.path is production's and is skipped for any other environment.
  3. Asks. Push .env.production (42 variables) to 203.0.113.10:/opt/shop/.env? and waits for y. Anything else prints Aborted. and changes nothing. --force skips the question.
  4. Uploads the file. As the deploy user, over the .env on the server. The whole file is replaced; nothing is merged and no backup is kept.
  5. Recreates the PHP services, only with --restart. See below.
  6. Prints a summary. Project, host, source, target and the number of variables.

What --restart restarts

More than the option's description says. The .env is mounted into every PHP container of the stack, and each of them caches its configuration when it starts. So --restart recreates all of them that the project has: app, horizon, scheduler and reverb. nginx and Redis are left running.

Without --restart the new file is on the server and the app keeps running on the old values, for as long as its containers live. That is useful when you want the change to arrive with the next release. It is confusing when you forget.

Recreating the containers takes the site away for a few seconds. On a busy shop, push without --restart and let the next grim release pick the values up.

Pitfalls

The server's file is replaced, not merged

A value a colleague set with grim env:set yesterday is not in the copy you pulled last week, and after your push it is not on the server either. There is no backup on the server to go back to. Pull right before you edit, and push soon after.

The guessed path is only a guess

With a host and no path, the target is /opt/<project> for production and /opt/<project>-staging for staging, which is where grim server:add-project puts them. A stack that was moved, or set up by hand somewhere else, is not found by guessing. Read the target in the question before you answer y, and write deploy.environments.<environment>.path into grim.json when it is wrong.

The question cannot be answered in a script

Run with --no-interaction, the question answers itself with no, and the command prints Aborted. and exits successfully. A pipeline that pushes needs --force.

There is nothing to push yet

.env.staging not found. means the local copy does not exist. Pull it first with grim env:pull staging, or write the file by hand when the environment is new.

After it finishes

With --restart the app is already running on the new values. Check the one you changed from inside the container. grim remote:artisan takes no environment and talks to the one registered on your machine, production in the usual case.

$ grim remote:artisan tinker --execute="echo config('mail.mailers.smtp.host');"

Then delete the local copy, or at least do not let it age. It holds production credentials, and the next person to push a stale one undoes somebody's work.

Recipes that use it