
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Shipping TypeScript applications without automated verification is a liability, not a strategy. A properly configured CI/CD pipeline for Deno with GitHub Actions eliminates manual testing drift and ensures every commit meets your quality bar before reaching production. This guide provides the exact workflow configuration, caching strategies, and security checks I use to maintain reliable Deno services, building on the automation principles covered in my build pipeline automation best practices.
How do you configure a CI/CD pipeline for Deno with GitHub Actions?
The foundation of any reliable Deno automation is a workflow file that respects the runtime's unique module resolution. Unlike Node.js, Deno does not rely on a local node_modules directory by default; it fetches and caches remote modules globally. Your CI/CD pipeline for Deno with GitHub Actions must explicitly manage this cache to avoid hitting rate limits and to ensure deterministic builds across runs.
Create the base workflow structure
Start with a clean YAML configuration at .github/workflows/deno-ci.yml. Pin the Deno version explicitly rather than using "latest" to prevent surprise breakages when new releases drop. The denoland/setup-deno action handles installation and path configuration correctly on all runner OS types.
name: Deno CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
DENO_VERSION: v2.1.4
DENO_DIR: .deno-cache
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: ${{ env.DENO_VERSION }}
- name: Cache Dependencies
uses: actions/cache@v4
with:
path: ${{ env.DENO_DIR }}
key: deno-${{ hashFiles('/deno.json', '/deno.lock') }}
restore-keys: deno-
- name: Verify Lockfile
run: deno install --locked
- name: Run Lint
run: deno lint
- name: Run Tests with Coverage
run: deno test --allow-all --coverage=coverage/
- name: Generate Coverage Report
run: deno coverage coverage/ --lcov > coverage.lcov This configuration enforces lockfile integrity with --locked, which fails the build if dependencies have drifted from what was committed. This is critical for supply chain security and aligns with the dependency management practices discussed in handling secrets and dependencies safely.
Manage environment permissions correctly
Deno's permission model is a feature, not a hindrance. In CI, you should grant only the permissions each step actually needs. Avoid blanket --allow-all flags in production build steps. For testing, --allow-all is often acceptable since tests need filesystem and network access, but your compile and deploy steps should be more restrictive. Document why each permission flag exists in your workflow comments so future maintainers understand the security posture.
How do you optimize Deno dependency caching in GitHub Actions?
Cache misses are the silent killer of pipeline velocity. Without proper caching, every run re-downloads every remote import, adding 30–90 seconds to jobs and creating external service dependencies that can fail independently of your code. The key is understanding that Deno stores fetched modules in DENO_DIR, not in your project directory.
The cache key must include both deno.json and deno.lock. Using only one creates stale cache scenarios where the lockfile changes but the manifest hash doesn't, or vice versa. The restore-keys fallback with just deno- allows partial cache restoration when dependencies change incrementally, which still saves significant time compared to a cold fetch. Always set DENO_DIR as an environment variable at the workflow level so every job references the same cached path consistently.
Avoid common caching pitfalls
- Never cache vendor directories blindly: If you use
deno vendor, cache the vendor folder separately with its own key derived from the lockfile hash. - Don't share caches across OS runners: Windows and Linux store paths differently. Include
runner.osin your cache key if you use matrix builds across platforms. - Monitor cache size: GitHub Actions has a 10 GB repository cache limit. Deno caches can grow large with many dependencies. Add a cleanup step or use scoped cache keys per job type.
- Validate cache restoration: Add a verification step after cache restore that runs
deno infoto confirm expected modules are present before proceeding.
How do you add security scanning to a Deno GitHub Actions workflow?
Security cannot be an afterthought in modern pipelines. Deno's URL-based imports introduce unique supply chain risks that traditional SAST tools miss. Your CI/CD pipeline for Deno with GitHub Actions should include dedicated steps for dependency auditing and secret detection that run in parallel with functional tests to avoid extending feedback loops.
Integrate gitleaks or trufflehog as early pipeline steps to catch accidentally committed credentials before they propagate. For dependency vulnerabilities, use deno audit (available in Deno 2.x) or third-party scanners that understand Deno's import map format. When deploying to cloud infrastructure, always use OpenID Connect (OIDC) instead of long-lived access keys, following the pattern described in deploying to AWS with OIDC. This eliminates static credential management entirely and provides short-lived, auditable tokens tied to specific workflow runs.
Add a software bill of materials (SBOM) generation step using deno info --json piped through SBOM tooling. This creates an artifact that compliance teams and security reviewers can inspect without needing to reconstruct your dependency graph manually. For teams operating under SOC 2 or ISO 27001 frameworks, this automated evidence collection is non-negotiable.
How do you deploy Deno applications automatically from GitHub Actions?
Deployment strategy depends entirely on your target platform, but the pipeline principles remain constant: deploy only after all quality gates pass, use immutable artifacts where possible, and maintain rollback capability. Deno compiles to single standalone binaries with deno compile, which simplifies deployment significantly compared to shipping source code plus runtime dependencies.
Compile for production deployment
- name: Compile Production Binary
run: |
deno compile \
--allow-net \
--allow-env \
--allow-read=/app/data \
--output dist/my-service \
src/main.ts
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: deno-binary-${{ github.sha }}
path: dist/my-service
retention-days: 30 The compiled binary includes the exact Deno runtime version and all dependencies frozen at build time. This eliminates runtime version drift between CI and production. Specify minimal permissions during compilation — this becomes your production security boundary regardless of server configuration.
Choose your deployment target wisely
| Platform | Best For | Deploy Method | Rollback Speed |
|---|---|---|---|
| Deno Deploy | Edge APIs, low-latency global | Native GitHub integration or CLI | Instant (version pinning) |
| AWS ECS/Lambda | Enterprise, existing AWS footprint | OIDC + ECR push + task update | Minutes (new task revision) |
| Kubernetes (EKS/GKE) | Microservices, complex orchestration | Helm/ArgoCD with image tag | Seconds (revision rollback) |
| VPS / Bare Metal | Cost-sensitive, Nepal-local hosting | SSH + systemd binary swap | Manual (keep previous binary) |
For teams serving users in Nepal or South Asia, consider latency implications carefully. Deno Deploy's edge network has limited PoPs in the region compared to Cloudflare or AWS Mumbai. Test actual latency from Kathmandu before committing to a platform. Sometimes a well-placed VPS in Singapore or Mumbai outperforms "global" edge networks for regional audiences. Read more about regional hosting considerations in hosting for Nepal audiences.
Implement safe rollback procedures
Every deployment step must preserve the previous working artifact. On VPS deployments, rename the current binary to my-service.bak before copying the new one. On Kubernetes, never delete the previous ReplicaSet immediately — keep at least two revisions available. On Deno Deploy, pin production to a specific deployment ID rather than auto-deploying from main. Automated rollbacks triggered by health check failures should revert to the last known good artifact within 60 seconds. Test your rollback procedure regularly; untested rollbacks are just hopes.
Building Resilient Deno Automation
A mature CI/CD pipeline for Deno with GitHub Actions is more than a YAML file — it's an expression of your team's engineering standards. Start with the base workflow and caching strategy outlined here, then layer in security scanning and deployment automation as your stability requirements grow. Measure your pipeline's cycle time weekly; if feedback takes longer than 10 minutes, optimize caching or parallelize independent jobs. If you need help designing a pipeline that meets compliance requirements or scales with your team, reach out to discuss your specific infrastructure needs.