August 1st, 2021 - 9 min read
We're taking How-to Dockerize your sveltekit app as the base for this post.
Please read that post first or check out the following tag. Either clone the repo and checkout that version or download the zip-file.
This is part one of two blog posts and here we're focusing on the Docker setup. In the second part we'll create the Svelte Todo app. So if you're more interested in the frontend app with Graphql you can directly start with the other post.
We're creating a basic to-do app with adding todos, deleting, and toggling the status.
The data will be stored in a PostgreSQL database and we're querying/mutating it with Graphql. We'll use Hasura as Graphql service. It will be used for the connection from Svelte to the Postgres SQL data.
Below is the complete
docker-compose.yml that we're having in the root directory.
I will explain every change after the snippet.
version: '3.9' services: web: build: ./app ports: - "80:3000" db: image: postgres restart: always volumes: - pgdata:/var/lib/postgressql/data ports: - "5432:5432" environment: POSTGRES_PASSWORD: $POSTGRES_PASSWORD graphql-engine: image: hasura/graphql-engine:v2.0.1.cli-migrations-v3 ports: - "8080:8080" depends_on: - db restart: always volumes: - ./hasura/migrations:/hasura-migrations - ./hasura/metadata:/hasura-metadata environment: HASURA_GRAPHQL_DATABASE_URL: $POSTGRES_URL HASURA_GRAPHQL_ENABLE_CONSOLE: "false" # Note: MIGRATIONS_DIR / METADATA_DIR only needed if we'd like to have a different location in the container # HASURA_GRAPHQL_MIGRATIONS_DIR: /hasura-migrations # HASURA_GRAPHQL_METADATA_DIR: /hasura-metadata ## uncomment next line to set an admin secret # HASURA_GRAPHQL_ADMIN_SECRET: $HASURA_ADMIN_SECRET adminer: image: adminer restart: always ports: - "8090:8080" volumes: pgdata:
db service, we changed the volume to
pgdata and add an empty
volumes: pgdata: at the end of the file. This will create persistence in a location of the Docker host by using the default driver (that's typically the local driver). For more details, see the volumes config docs.
graphql-engine service will use the
hasura image. Port is directly mapped to 8080 on the host.
depends_on means that the service can only be started if the
db service is running. This is needed as Hasura needs the database to work with.
restart: always will restart the service if it was stopped.
volumes we're mapping folders of our project root that we'll create, so we're having our migrations in place. Migrations are used to initialize our database.
We don't need to add these folders manually. We're adding them with the Hasura CLI.
Adminer service could be removed because Hasura can replace this completely. But for now, we change the host port to 8090, so there is no conflict with the
There are some environment variables to configure Hasura:
HASURA_GRAPHQL_ENABLE_CONSOLE: If "true" the service will start the console.
HASURA_METADATA_DIR: Specifes the location of our migrations / metadata - optional, using default location (see Hasura Migrations section below for more details)
HASURA_ADMIN_SECRET: If set there should be a password in the console - I haven't tested this.
.env file in the project root:
# POSTGRES config POSTGRES_PASSWORD=password POSTGRES_URL=postgres://postgres:password@db:5432/postgres # Hasura config # HASURA_ADMIN_SECRECT=...
Side note to the graphql-engine service
You can further improve this setup by adding docker-compose-wait and wait for the
dbport 5432. In a
hasurafolder. This is left as an exercise but will be available in the final code.
This will improve startup as
depends_ononly says that the service is running but not if the port is accessible. Without waiting the
graphql-enginewill likely restart multiple times until the port is ready.
Install Hasura CLI with
npm install --global hasura-cli. Next, check that
HASURA_GRAPHQL_ENABLE_CONSOLE is set to "false". That's needed to work with the migrations. It tells the service that there is no need to start the console on port 8080 as we're using the CLI to manage and start the console for local development.
graphql-engine and run
hasura init hasura --endpoint http://localhost:8080 inside the project root.
This will create a subfolder
hasura where the migrations/metadata are stored.
Avira Antivirus heuristic quarantined Hasura on Windows 10. Reducing the heuristic level from medium to low fixed this false-positive.
Change to the
hasura directory and run
hasura console. This opens a console that will be connected to the
Click on data tab and create the table. Fill the field like in the below screenshot by adding:
Add as method
gen_random_uuid to the
id so the backend will use that method to generate the unique id. It will generate a UUID_v4 for every new row.
created_at will use a UTC timestamp by using now() as default method. The
::timestamp ensures that it is a UTC timestamp. For the timestamp type, you could also use
time without time zone but in Postgres SQL timestamp will always default to the UTC timestamp.
Or even better, use the type
time with-out time zone and use as default the following with braces
(now() at time zone 'utc') so it's crystal clear that your storing the
created_at field as UTC timestamp. For more details, have a look at the following SO answer.
Add table. There is a
todo table in the console and if you're looking in your
hasura folder you will see the added migration & metadata that were created - we're using this to initially create our database.
To run the migrations on Docker start, it's important to use the Hasura image with
.cli-migrations-v3 in its name. This will include
/bin/hasura-cli so it will automatically run the migrations on startup.
The service will use the migrations located at the default location
/hasura-metadata - we could change this with the environment variables and the volumes keys. (It's the location inside the container that's why there is the slash pointing to the root folder.)
Some words to the migrations config version, we're using v3 here as it is the latest version. But v2 will also work, the main difference is that in v3 migration config supports multiple databases - so the migrations are more complicated.
But if you're not planning to create the migrations manually, I'd use version 3 as the Hasura console will generate everything for us.
Note: Don't be confused by v3 not selectable in the Hasura docs, v3 is the version of the migration config and not the Hasura version v1.x/v2.x.
Follow the Hasura docs.
For step 3 use the following SQL (no id required because the DB will generate UUIDs):
INSERT INTO todo (title, completed, created_at) VALUES ('Learn Svelte', false, now() - interval '2 second'), ('Learn Docker', false, now() - interval '1 second'), ('Learn Graphql', true, now());
We're adding the
created_at with intervals so we're having different timestamps.
Learn Graphql is the newest entry as it's using
now() directly. This is only relevant for seeding.
Before running the SQL insert, don't forget to select "This is a migration" checkbox and pick a name e.g.
insert_seed_todos. This will add the insert as migration.
Now, click run and have a look in the
hasura\migrations folder. The
insert_seed_todos should be added there.
The new data will be also displayed in the data tab of the console with three new entries.
Change into the
hasura folder and run
hasura console or change
"true" and restart the
The CLI will automatically open the console and for the other approach go to
localhost:8080 to have the console. (Use the first one if you're using migrations and you want the changes to persist.)
Click on API tab to get to a GraphQL playground. On the bottom left, you can select query, mutation, or subscription and after hitting the plus. It's possible to customize the query and run it with the play button.
In the data route, you can view, add, edit, or delete your data. The action tab can be used to configure custom business logic and the events are triggered on data change (if configured in that tab). For more details on actions and events, please have a look at the Hasura docs
Some tips to issues I've had during development and how to fix them:
failed to get version from server: failed making version api callduring start of
hasura console: Check that Docker compose started and everything is running correctly. Also check if
http://localhost:8080/v1/versionis available in a browser - maybe the
graphql-engineis not started and you're just starting the cli console too early.
Hasura consolenot starting & uninstalling not working. Manually remove
c:\program files\nodejs\(3 files, hasura, hasura.cmd & hasura.ps1) and reinstall with
npm i -g hasura-cli
The Docker setup is working as expected and is a good starting point for new apps with Svelte & Postgres SQL.
If your setup is working properly you should now have at least 3 running services (with-out Adminer):
The best way to check the setup is by using the Hasura console and test the Graphql playground.
So the Docker setup is finished. Now, we can focus on the frontend app with Svelte.
You can continue with part 2.