Skip to main content
Deno is a modern JavaScript/TypeScript runtime with built-in support for TypeScript, web standards, and secure-by-default execution. Remix works natively on Deno without any adapters.

Prerequisites

Running Locally

Create a server entry point:
server.ts
import { createRouter } from 'npm:remix/fetch-router'
import { route } from 'npm:remix/fetch-router/routes'

let routes = route({
  home: '/',
  about: '/about',
})

let router = createRouter()

router.map(routes, {
  actions: {
    home() {
      return new Response('Hello from Deno!')
    },
    about() {
      return new Response('About page')
    },
  },
})

Deno.serve({ port: 3000 }, (request) => router.fetch(request))
Run your server:
deno run --allow-net --allow-read server.ts

Import Maps

For better dependency management, use import maps:
deno.json
{
  "imports": {
    "remix/": "npm:[email protected]/"
  },
  "tasks": {
    "dev": "deno run --allow-net --allow-read --allow-env --watch server.ts",
    "start": "deno run --allow-net --allow-read --allow-env server.ts"
  }
}
Simplify imports:
import { createRouter } from 'remix/fetch-router'
import { route } from 'remix/fetch-router/routes'
Run with:
deno task dev

Permissions

Deno requires explicit permissions. Common permissions for Remix apps:
  • --allow-net: Network access
  • --allow-read: File system reads
  • --allow-write: File system writes
  • --allow-env: Environment variable access

Deploy to Deno Deploy

Deno Deploy is a globally distributed serverless platform.

Deploy with GitHub

  1. Push your code to GitHub
  2. Visit https://dash.deno.com/
  3. Click “New Project”
  4. Connect your GitHub repository
  5. Set entry point to server.ts
  6. Deploy!

Deploy with CLI

Install deployctl:
deno install --allow-all --no-check -r -f https://deno.land/x/deploy/deployctl.ts
Deploy:
deployctl deploy --project=my-remix-app server.ts

Environment Variables

Set environment variables in Deno Deploy dashboard or use .env files locally:
import { load } from 'https://deno.land/[email protected]/dotenv/mod.ts'

await load({ export: true })

let databaseUrl = Deno.env.get('DATABASE_URL')
let sessionSecret = Deno.env.get('SESSION_SECRET')

KV Database

Deno Deploy includes a built-in KV database:
let kv = await Deno.openKv()

// Set values
await kv.set(['users', 'alice'], { name: 'Alice', email: '[email protected]' })

// Get values
let user = await kv.get(['users', 'alice'])

// List keys
for await (let entry of kv.list({ prefix: ['users'] })) {
  console.log(entry.key, entry.value)
}

Static Files

Serve static files with the static middleware:
import { staticFiles } from 'remix/static-middleware'

let router = createRouter({
  middleware: [staticFiles('./public')],
})

TypeScript Configuration

Create a deno.json for TypeScript settings:
{
  "compilerOptions": {
    "lib": ["deno.window"],
    "strict": true
  },
  "fmt": {
    "useTabs": false,
    "lineWidth": 100,
    "indentWidth": 2,
    "singleQuote": true
  }
}

Best Practices

  • Use import maps for cleaner imports
  • Request only necessary permissions
  • Leverage Deno KV for edge data
  • Use deno fmt and deno lint
  • Cache dependencies with DENO_DIR

Development Workflow

# Run with auto-reload
deno task dev

# Format code
deno fmt

# Lint code
deno lint

# Run tests
deno test

Runtime Agnostic

How Remix runs on any JavaScript runtime

Fetch Router

Router API reference

Build docs developers (and LLMs) love