Edit

+server

Define +server.js to seamlessly integrate a server framework (Hono, Express.js, ...). Or set +server: true to use Vike's built-in lightweight server.

Using +server is the recommended way for a seamless server integration, but you can also use renderPage() to manually integrate the server instead.

vike-photon is deprecated — it has been replaced by +server:

Get started

+server.js

Define +server.js to integrate a server:

npm install hono @vikejs/hono
pnpm add hono @vikejs/hono
bun add hono @vikejs/hono
yarn add hono @vikejs/hono
// +server.js
 
import { Hono } from 'hono'
import vike from '@vikejs/hono'
 
const app = new Hono()
vike(app) // Attaches Vike
 
export default {
  fetch: app.fetch
}
// +server.ts
 
import { Hono } from 'hono'
import vike from '@vikejs/hono'
import type { Server } from 'vike/types'
 
const app = new Hono()
vike(app) // Attaches Vike
 
export default {
  fetch: app.fetch
} satisfies Server

+server: true

Alternatively, instead of creating +server.js, you can use Vike's built-in lightweight server:

// pages/+config.js
 
export default {
  server: true // Use Vike's built-in server
}
// pages/+config.ts
 
export default {
  server: true // Use Vike's built-in server
}

Deployment

Self-host

# Build for production
vike build
# Run the production build
node ./dist/server/index.mjs # or Bun/Deno

Deployment providers

Settings

All settings are defined over export default { prod: { /*...*/ } }:

// +server.js
 
export default {
  // Production settings
  prod: {
    // Server port, defaults to 3000. It's ignored on Cloudflare and Vercel Edge (there
    // isn't any server in serverless deployments).
    port: 3000,
 
    hostname: 'localhost',
 
    // Called once the server is accepting connections.
    // - The `server` object comes from srvx, see https://srvx.h3.dev/guide/server
    // - This hook isn't called on Cloudflare and Vercel Edge (there isn't
    //   any server in serverless deployments).
    onReady(server) {
      console.log('Server is ready.')
    },
 
    // Called once the server is created.
    // - The `server` object comes from srvx, see https://srvx.h3.dev/guide/server
    // - This hook isn't called on Cloudflare and Vercel Edge (there isn't
    //   any server in serverless deployments).
    onCreate(server) {
      console.log('Server created.')
    },
 
    // HTTPS Options (Node.js/Bun/Deno)
    tls: {
      // For example SSL/TLS key and certificate for HTTPS
      key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
      cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem'),
      // Optional
      passphrase: 'passphrase'
    },
 
    // Serve static files automatically
    static: true, // Default value
    // Can be disabled:
    static: false,
    // Or serve from a custom folder:
    static: './public'
  }
}
// +server.ts
 
import type { Server } from 'vike/types'
 
export default {
  // Production settings
  prod: { 
    // Server port, defaults to 3000. It's ignored on Cloudflare and Vercel Edge (there
    // isn't any server in serverless deployments).
    port: 3000,
 
    hostname: 'localhost',
 
    // Called once the server is accepting connections.
    // - The `server` object comes from srvx, see https://srvx.h3.dev/guide/server
    // - This hook isn't called on Cloudflare and Vercel Edge (there isn't
    //   any server in serverless deployments).
    onReady(server) {
      console.log('Server is ready.')
    },
 
    // Called once the server is created.
    // - The `server` object comes from srvx, see https://srvx.h3.dev/guide/server
    // - This hook isn't called on Cloudflare and Vercel Edge (there isn't
    //   any server in serverless deployments).
    onCreate(server) {
      console.log('Server created.')
    },
 
    // HTTPS Options (Node.js/Bun/Deno)
    tls: {
      // For example SSL/TLS key and certificate for HTTPS
      key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
      cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem'),
      // Optional
      passphrase: 'passphrase'
    },
 
    // Serve static files automatically
    static: true, // Default value
    // Can be disabled:
    static: false,
    // Or serve from a custom folder:
    static: './public'
  }
} satisfies Server

The above settings only apply to production. For development, use Vite's server settings.

🚧 Server settings are separate because values usually differ between dev and prod. If you have a use case where settings share the same value in dev and prod, then reach out and we'll create server settings that apply to both dev an prod.

pageContext.runtime

You can use pageContext.runtime to access the HTTP request object, for example:

// pages/product/@id/+data.js
 
export async function data(pageContext) {
  // Using pageContext.runtime.req to access the logged-in user
  const { user } = pageContext.runtime.req
  // ...
}
// pages/product/@id/+data.ts
 
import type { PageContextServer } from 'vike/types'
 
export type Data = Awaited<ReturnType<typeof data>>
export async function data(pageContext: PageContextServer) {
  // Using pageContext.runtime.req to access the logged-in user
  const { user } = pageContext.runtime.req
  // ...
}
 
declare global {
  namespace Vike {
    interface Server {
      // 👉 Pick your server (for correct pageContext.runtime type)
      server: 'hono' // | 'express' | 'fastify' | 'hattip' | 'srvx' | 'elysia' | 'h3'
    }
  }
}

You can use +onCreatePageContext to define custom pageContext properties, see API > pageContext > Custom.

For example, you can define pageContext.user as an alias of pageContext.runtime.req.user for convenience, see Integration > Authentication > pageContext.user.

See also:

Standalone

Use standaloner to have the build output directory (dist/) contain everything needed for deployment. This means that, in production, only the dist/ directory is required (you can remove node_modules/ and skip $ npm install).

Skipping node_modules/ massively reduces disk usage in production, which can be important, for example to reduce the size of Docker images.

npm install standaloner
pnpm add standaloner
bun add standaloner
yarn add standaloner
// vite.config.js
 
import { defineConfig } from 'vite'
import standaloner from 'standaloner/vite'
 
export default defineConfig({
  plugins: [
    standaloner() 
  ]
})
// vite.config.ts
 
import { defineConfig } from 'vite'
import standaloner from 'standaloner/vite'
 
export default defineConfig({
  plugins: [
    standaloner() 
  ]
})

HMR

If you change a server file, the server code is automatically updated: the next HTTP response will be generated by the latest server code. No full server reload is required.

If HMR isn't what you want (for example if you modify the database connection) you can manually trigger a full server reload by pressing r + enter.

Compression

You can compress all server responses by using the compress universal middleware:

npm install @universal-middleware/compress
pnpm add @universal-middleware/compress
bun add @universal-middleware/compress
yarn add @universal-middleware/compress
// +server.js
 
import { Hono } from 'hono'
import vike from '@vikejs/hono'
import compress from '@universal-middleware/compress'
 
const app = new Hono() 
// Add universal middlewares here (same for Express.js, Fastify, ...)
vike(app, [compress()]) 
// +server.ts
 
import { Hono } from 'hono'
import vike from '@vikejs/hono'
import compress from '@universal-middleware/compress'
 
const app = new Hono() 
// Add universal middlewares here (same for Express.js, Fastify, ...)
vike(app, [compress()]) 

See also