Deploying encore.ts application on dokploy
16 December 2025 (Today)
This guide explains how to deploy your Encore application to Dokploy using `dotenvx` for managing secrets.
Prerequisites
- Encore application: One can create using
encore app create . Make sure it is running and build passing. If you are using pub/sub or postgres or other infra, create a config.json - Encrypted .env: I personally use dotenvx to handle my secrets. i can install it
bun add @dotenvx/dotenvx, it encrypts the enviroment variablesbunx dotenvx encrypt to be used in the encore application just by callingprocess.env.secret andimport '@dotenvx/dotenvx/config' at the top of helper component. Ensure your.env file is encrypted before deployment and can be committed to the repository to pass the encore build (Note: do add.env.keys in.gitignorethis is main secret which decrypts variables).
Deployment Steps
1. Create Github action workflow
This action workflow .github/workflows/docker.yml will create the docker-image and push it to the github container registry. We will then use this image to deploy our application. A webhook can be later added to trigger new deployment on every new image is published using this action workflow.
name: Build & Push Docker Image
on:
push:
tags: ["v*.*.*"]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.3.4
- name: Install Encore
run: |
curl -L https://encore.dev/install.sh | bash
echo "/home/runner/.encore/bin" >> $GITHUB_PATH
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.ACTION_GITHUB_TOKEN }}
- name: Lowercase Image Name
run: echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Build Docker image with Encore
run: |
encore build docker --arch arm64 --config ./config.json --push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
encore build docker --arch arm64 --config ./config.json --push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Trigger dokploy deployment
run: curl -X POST https://dokploy.example.com/api/deploy/compose/....
This workflow triggers on every new tag v*.*.* is published on the github. This can be automated running bun run bump where bumpis a package.json script "bump": "bunx bumpp --execute 'git add .' --commit 'chore: release v%s' --tag 'v%s' && git push --follow-tags".
Further, i am using the QEMU for virtualization of arm64 on non-arm github-action device, one can always use ubuntu-24.04-arm for github actions (not available for private repo though now) or whatever is the arch of the virtual machine.
Note that: One need to add a github action secrets ACTION_GITHUB_TOKENwhich is a personalized token to have delete:packages, repo, workflow, write:packages access.
2. Configure Dokploy
If you want to deploy the full stack (API + Database + PubSub/NSQ), use the Compose deployment in Dokploy:
-
Create a New Service: Choose Compose (sometimes called "Stack").
-
Copy Configuration: Copy the contents of your
docker-compose.ymlinto the raw editor.services: api: image: ghcr.io/<github-username>/<repo-name>:latest container_name: encore_app ports: - 4000:8080 environment: - NSQD_ADDRESS=nsqd:4150 - DOTENV_PRIVATE_KEY=${DOTENV_PRIVATE_KEY} depends_on: - nsqd command: - /app/service labels: - traefik.docker.network=dokploy-network - traefik.http.routers.apiencore-api-lyurgk-50-web.rule=Host(`api.example.com`) - traefik.http.routers.apiencore-api-lyurgk-50-web.entrypoints=web - traefik.http.services.apiencore-api-lyurgk-50-web.loadbalancer.server.port=8080 - traefik.http.routers.apiencore-api-lyurgk-50-web.service=apiencore-api-lyurgk-50-web - traefik.http.routers.apiencore-api-lyurgk-50-web.middlewares=redirect-to-https@file - traefik.http.routers.apiencore-api-lyurgk-50-websecure.rule=Host(`api.example.com`) - traefik.http.routers.apiencore-api-lyurgk-50-websecure.entrypoints=websecure - traefik.http.services.apiencore-api-lyurgk-50-websecure.loadbalancer.server.port=8080 - traefik.http.routers.apiencore-api-lyurgk-50-websecure.service=apiencore-api-lyurgk-50-websecure - traefik.http.routers.apiencore-api-lyurgk-50-websecure.tls.certresolver=letsencrypt - traefik.enable=true networks: - dokploy-network nsqd: image: nsqio/nsq container_name: nsqd command: /nsqd networks: - dokploy-network nsqlookupd: image: nsqio/nsq container_name: nsqlookupd command: /nsqlookupd networks: - dokploy-network nsqadmin: image: nsqio/nsq container_name: nsqadmin command: /nsqadmin --lookupd-http-address=nsqlookupd:4161 depends_on: - nsqlookupd networks: - dokploy-network // add other services like postgres or other ... networks: dokploy-network: external: true -
Environment Variables:
- Set
DOTENV_PRIVATE_KEY in the environment variables tab (Use the value from.env.keys labeledDOTENV_PRIVATE_KEY).
- Set
-
Deploy: Dokploy will pull the image from
ghcrand start all services (API, Postgres, NSQ).
3. Set Environment Variables
In the Environment tab of your Dokploy service:
Add a single environment variable:
- Key:
DOTENV_PRIVATE_KEY - Value: `k0_...` (The key you retrieved in Step 1)
dotenvx will automatically detect this variable at runtime and decrypt your .env file.
4. Deploy
Click Deploy!
Check the logs. You should see [dotenvx] injecting env ... indicating successful decryption.
Troubleshooting
"Missing .env file"
If the logs say the file is missing:
- Ensure you committed the
.envfile to git. - Verify
encore build docker included the file. Encore's build process usually packages the application code. Ifdotenvxfails to find the file, we may need to explicitly verify the Docker image contents.