Framework for
Stability and Freedom
Minimal-lock-in framework that prioritizes application stability and development freedom, powered by an open foundation built for JavaScript's rapidly evolving ecosystem.
We started Vike 5 years ago with a bold mission: build the last framework you'll need — a rock-solid foundation with powerful hooks, ready to embrace JavaScript's future.
Freedom
Your stack, your choice
- Any frontend: React/Vue/Solid/...
- Any rendering: SPA/SSG/SSR/...
- Any API: RPC/REST/GraphQL
- Any backend: Hono/Express.js/Laravel/Java/...
- Any deployment: Self-hosted/Cloudflare/Vercel/...
Supported tools
Supported stacks
Powerful hooks
Use powerful hooks for unprecedented flexibility and extensive control over tool integration, data lifecycle, pre-rendering, state management, and more.
Hooks unlock unprecedented deep integrations — use them directly for maximum control, or via Vike extensions such as vike-react and vike-react-apollo for zero-config integration.
Supported use cases
Stable foundation
Vike internal components
JavaScript ecosystem
Vike's internal components are stable features that remain relevant for the foreseeable future, making Vike a stable foundation.
Fast evolving JavaScript tools aren't built into Vike by design — instead, Vike extensions provide deep and first-class integrations via powerful hooks.
Stable stack or cutting edge?
Your choice.
Choose between a stable stack with unmatched long-term support (thanks to Vike's stable foundation), or the cutting-edge with unprecedented flexibility (thanks to Vike's powerful hooks).
Legacy support
Cutting-edge support
Stable interests
Upfront and transparent pricing you can trust, instead of hidden monetization lock-in mechanisms.
It's the guarantee Vike's interests are and remain aligned with yours.
Lightning DX
First-class SSR/SPA/SSG
Toggle SSR/SPA/SSG on a page-by-page basis, powered by config inheritance.
/pages/product/+config.js
# SSR pages
/pages/product/@id/+Page.js # URL: /product/42
/pages/product/@id/buy/+Page.js # URL: /product/42/buy
/pages/admin/+config.js
# SPA pages (i.e. SSR disabled)
/pages/admin/products/+Page.js # URL: /admin/products
/pages/admin/users/+Page.js # URL: /admin/users
/pages/(marketing)/+config.js
# SSG pages (i.e. pre-rendering)
/pages/(marketing)/index/+Page.js # URL: /
/pages/(marketing)/about/+Page.js # URL: /about // /pages/product/+config.js
// » config for product pages: /pages/product/**/+Page.js
export default {
ssr: true
}// /pages/admin/+config.js
// » config for admin pages: /pages/admin/**/+Page.js
export default {
ssr: false // => SPA
}// /pages/(marketing)/+config.js
// » config for marketing pages: /pages/(marketing)/**/+Page.js
export default {
prerender: true // aka SSG
}API
First-class RPC
Next-gen RPC (aka Server Functions) with Telefunc (maintained by the Vike team), or classic RPC with tools such as tRPC.
// CreateTodo.telefunc.ts
// Environment: server
// Telefunc makes onNewTodo() remotely callable
// from the browser.
export { onNewTodo }
import { getContext } from 'telefunc'
// Telefunction arguments are automatically validated
// at runtime, so `text` is guaranteed to be a string.
async function onNewTodo(text: string) {
const { user } = getContext()
// With an ORM
await Todo.create({ text, authorId: user.id })
// With SQL
await sql(
'INSERT INTO todo_items VALUES (:text, :authorId)',
{ text, authorId: user.id }
)
}// CreateTodo.tsx
// Environment: client
// CreateTodo.telefunc.ts isn't actually loaded;
// Telefunc transforms it into a thin HTTP client.
import { onNewTodo } from './CreateTodo.telefunc.ts'
async function onClick(form) {
const text = form.input.value
// Behind the scenes, Telefunc makes an HTTP request
// to the server.
await onNewTodo(text)
}
function CreateTodo() {
return (
<form>
<input input="text"></input>
<button onClick={onClick}>Add To-Do</button>
</form>
)
}First-class REST
Consume REST APIs with Vike's built-in hook +data, or with extensions such as vike-react-query / vike-vue-query / vike-solid-query.
// Powered by vike-react-query
import { useSuspenseQuery } from '@tanstack/react-query'
const Movie = ({ id }) => {
const result = useSuspenseQuery({
queryKey: ['movie', id],
queryFn: () =>
fetch(`https://swapi.info/api/films/${id}`)
.then((res) => res.json())
})
const { title } = result.data
return (
<div>
Title: <b>{title}</b>
</div>
)
}First-class GraphQL
Consume GraphQL APIs with extensions such as vike-react-apollo, or with a custom integration.
// Powered by vike-react-apollo
import { useSuspenseQuery, gql } from '@apollo/client'
const Countries = () => {
const { data } = useSuspenseQuery(gql`
{
countries {
code
name
}
}
`)
return (
<ul>
{data.countries.map((country) => (
<li key={country.code}>{country.name}</li>
))}
</ul>
)
}Hooks
Data fetching: where
Hooks give you control where data is fetched:
// /pages/movie/@id/+data.server.js
// Environment: server
export async function data(pageContext) {
const { id } = pageContext.routeParams
// Fetching data on the server-side
const movie = await Movie.find({ where: { id } })
return { movie }
}// /pages/movie/@id/+data.client.js
// Environment: client
export async function data(pageContext) {
const { id } = pageContext.routeParams
// Fetching data on the client-side
const movie = await (
await fetch(`https://swapi.info/api/films/${id}`)
).json()
return { movie }
}Data fetching: when
Also control when data is fetched. When server starts:
// /pages/+onCreateGlobalContext.server.js
// Environment: server
export async function onCreateGlobalContext() {
globalContext.someServerData = await fetchSomeData()
}When client-side navigation starts:
// /pages/+onCreateGlobalContext.client.js
// Environment: client
export async function onCreateGlobalContext() {
globalContext.someClientData = await fetchSomeData()
}globalContext is accessible anywhere:
import { getGlobalContext } from 'vike'
const { someGlobalData } = await getGlobalContext()Authorization
// /pages/admin/+guard.js
// Applies to all admin pages: /pages/admin/**/+Page.js
import { render } from 'vike/abort'
export async function guard(pageContext) {
if (!pageContext.user.isAdmin) {
throw render(401, "Access forbidden")
}
}Instrumentation
// pages/+onHookCall.server.js
// Environment: server
// Called whenever a Vike hook is executed.
export async function onHookCall(hook, pageContext) {
console.log('before', hook.name, hook.filePath)
await hook.call()
console.log('after', hook.name, hook.filePath)
}Server integration
Vike is just a middleware you can embed into any server.
import { renderPage } from 'vike/server'
// Any server: Hono, Express.js, Cloudflare Worker, ...
server.addMiddleware({
method: 'GET',
route: '*', // catch-all
async handler(request) {
const pageContextInit = { urlOriginal: request.url }
const pageContext = await renderPage(pageContextInit)
const { body, statusCode } = pageContext.httpResponse
const response = { body, statusCode }
return response
}
})i18n
Full control over i18n integration.
// pages/+onBeforeRoute.js
export function onBeforeRoute(pageContext) {
console.log(pageContext.urlOriginal) // /de-DE/filme
const ret = extractLocale(pageContext.urlOriginal)
const { urlWithoutLocale, locale } = ret
console.log(locale) // de-DE
console.log(urlWithoutLocale) // /movie
// Make locale available as pageContext.locale
pageContext.locale = locale
// Vike's router will use pageContext.urlLogical
// instead of pageContext.urlOriginal
pageContext.urlLogical = urlWithoutLocale
}Powerful extensions
UI frameworks
Use your favorite UI framework via an extension for getting started quickly, or integrate it manually for maximum flexibility.
vike-react / vike-vue / vike-solidAdvanced integrations
Extensions can use all powerful hooks for advanced integrations such as React Server Components.
vike-react-rscState management
Powerful hooks also enable extensions to deeply integrate with state management tools with unprecedented seamless DX.
vike-react-redux / vike-react-zustand / vike-vue-piniaimport {
// Same as Zustand's create() but with
// seamless SSR integration
create
} from 'vike-react-zustand'
interface Store {
counter: number
increment: () => void
}
export const useStore = create()((set) => ({
counter: 0,
increment: () => set((state) =>
({ counter: state.counter + 1 })
)
}))Error tracking
THe hooks +onError, +onHookCall , and +onCreateGlobalContext enable extensions (and users) deep integration with error tracking.
For example, vike-react-sentry is a full-fledged Sentry integration:
- Browser & server error tracking
- Performance monitoring and tracing
- Automatic source map upload
Full-fledged
Data fetching
HTML streaming
react-streaming), Web Stream & Node.js Stream.Client-side Routing
history.pushState(), supports URL text fragments.Config inheritance
Pre-rendering (aka SSG)
Server-Side Rendering (SSR)
Redirections
Routing
Base URL
Internationalization (i18n)
+onBeforeRoute for full control over i18n.Instrumentation
Layouts
Link prefetching
Asset preloading
CSP
Any JavaScript runtime
Rich context objects
Fault tolerant
Infinite loop protections
Conservative browser support
@vitejs/plugin-legacy.Skew protection
Helpful warnings & errors
Hackable
pageContext.dangerouslyUseInternals.