Skip to main content
Get up and running with Remix in minutes. This guide will walk you through creating a simple web application with routing, middleware, and database queries.

Installation

Install Remix using your preferred package manager:
npm install remix

Create Your First Server

Create a file called server.ts:
server.ts
import { createRouter } from 'remix/fetch-router'
import { route } from 'remix/fetch-router/routes'
import { createServer } from 'remix/node-fetch-server'

// Define your routes
let routes = route({
  home: '/',
  about: '/about',
  api: {
    users: '/api/users',
  },
})

// Create router
let router = createRouter()

// Map routes to actions
router.map(routes, {
  actions: {
    home() {
      return new Response('Welcome to Remix!')
    },
    about() {
      return new Response('About Remix')
    },
    api: {
      actions: {
        users() {
          return Response.json({ users: ['Alice', 'Bob'] })
        },
      },
    },
  },
})

// Create and start server
let server = createServer(router)
server.listen(3000)
console.log('Server running at http://localhost:3000')

Run Your Server

node server.ts
Visit http://localhost:3000 to see your application running!

Add Middleware

Add logging middleware to track requests:
server.ts
import { createRouter } from 'remix/fetch-router'
import { logger } from 'remix/logger-middleware'

let router = createRouter({
  middleware: [
    logger('%date %method %path %status %response-time ms'),
  ],
})

// ... rest of your routes

Type-Safe Routing

Generate type-safe links using the href() method:
import { route } from 'remix/fetch-router/routes'

let routes = route({
  home: '/',
  post: '/posts/:id',
})

// Generate URLs
console.log(routes.home.href())        // "/"
console.log(routes.post.href({ id: '123' }))  // "/posts/123"

Add a Database

Install a database adapter:
npm install pg
Define your schema and create a database connection:
db.ts
import { Database } from 'better-sqlite3'
import { createDatabase, table, column as c } from 'remix/data-table'
import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'

// Define tables
let users = table({
  name: 'users',
  columns: {
    id: c.integer(),
    name: c.varchar(255),
    email: c.varchar(255),
  },
})

// Create database
let sqlite = new Database('./app.db')
let db = createDatabase(createSqliteDatabaseAdapter(sqlite))

export { db, users }
Use in your routes:
import { db, users } from './db'

router.get(routes.api.users, async () => {
  let allUsers = await db.findAll(users)
  return Response.json(allUsers)
})

router.post(routes.api.users, async ({ request }) => {
  let data = await request.json()
  let user = await db.create(users, data)
  return Response.json(user, { status: 201 })
})

Add Sessions

Add session management for authentication:
import { session } from 'remix/session-middleware'
import { createCookie } from 'remix/cookie'
import { createMemorySessionStorage } from 'remix/session'

let sessionCookie = createCookie('session', {
  secrets: [process.env.SESSION_SECRET!],
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'lax',
})

let router = createRouter({
  middleware: [
    session({
      storage: createMemorySessionStorage(),
      cookie: sessionCookie,
    }),
  ],
})

Next Steps

Core Concepts

Learn about Remix’s architecture and design principles

Routing Guide

Master type-safe routing and middleware

UI Components

Build reactive UIs with signals-based components

API Reference

Explore the complete API documentation

Need Help?

Build docs developers (and LLMs) love