initialDeployHook lifecycle and setup

I’m starting to use Preview Environments, and would like to seed the database.
I found initialDeployHook on the official docs and in community posts.

  1. Does the initialDeployHook script only run for preview environments or all does this field affect all environments?
  2. When does initialDeployHook run? Some of the posts I found say after startCommand some say before. For the first deploy is the flow: initialDeployHook → buildCommand → startCommand?
  3. Most examples I see sets initialDeployHook on a service, can it be set on the database config in render.yaml?
  - name: postgres
    previewPlan: starter
    initialDeployHook: "./scripts/"

My stack and current flow for context on my questions:

  • Django Backend
  • Postgres DB

I have a cron that stores db backups in S3 forked and modified from this: GitHub - render-examples/postgres-s3-backups. I’ve written my initialDeployScript to download and backfill my postgres db with the daily backup.

The next step I’m trying to understand is if my initialDeployHook needs to re-run my django migrations, which currently run in my buildCommand (as suggested here: Getting Started with Django on Render | Render), and if I need to add safety checks in my script to only run if it’s a render preview environment.

Related Posts:

My understanding is initialDeployHook runs on all environments, including Preview Environments.

Our initialDeployHook is setup to sync the database from S3 for preview environments only and run migrations for all environments.

buildCommand: ./bin/
initialDeployHook: "bundle exec rails sync_database; bundle exec rails db:migrate;" has code like this:

# If this is not the master branch, enforce the REVIEW_APP to be true
if [ "$RENDER_GIT_BRANCH" != "master" ]; then
  printf "\n==> Setting REVIEW_APP=enabled since deploying to a non-master branch\n\n"
  export REVIEW_APP=enabled

if [ "$REVIEW_APP" != "enabled" ]; then
  printf "\n==> Running pending database migrations\n\n"
  bundle exec rake db:migrate
  printf "\n==> Skipping db:migrate\n\n"

sync_database has code to skip any sync if it’s a production environment.

So if you look at the above, when you first launch a preview environment, we will grab our DB snapshot from S3 and sync it. Then run any DB migrations that preview environment might have for it.

For any subsequent to preview environments (like pushes to PR), runs any DB migrations that might be outstanding.

My understanding is the following run order:

  1. buildCommand
  2. startCommand
  3. initialDeployHook

So technically, the web server is running in a preview environment while the seed database is being restored. We tell our developers to not touch the preview environment until the seed database is done restoring, else you write to the DB while it’s being restored – and usually breaks the app and you have to start all over again.

We’re working on a new enhancement to display a maintenance page while the database is still being restored.

Thanks Conrad!

  1. Glad to see other folks have a similar setup as I’m planning, it was hard to find examples online/in the community of someone actually running this with their team. I’ll move forward with what you shared, since it seems to be a good workflow!

  2. You should document your setup, it’d be a medium / engineering blog post I’d definitely read + share :pray:

  3. Re run order: the order you shared jives with what I saw in one of the posts I linked, but in different one a render support agent said after the first deploy and before start command. Could be an honest mistake, or I’m misunderstanding the flow :woman_shrugging: – I may reach out to render support directly later to get the “official” word.

Forgot to ask, if you’re open to sharing here, how do you handle environment variables for your preview branch?

Unfortunately, we have to overload both development and production environmental variables into the preview apps. So imagine you have a two API keys for dev and production for some service. Our preview environments carry both of them and are just suffixed SOME_API_KEY_DEV and SOME_API_KEY_PROD

Not very elegant. Ideally, these staging environments should not carry production keys.

We only do this approach with one API. In general, we limit the number of APIs that get this and just have a single key that shared between staging/production and we restrict access through other means.