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.
They unlock unprecedented deep integrations — use them directly for maximum control, or use Vike extensions such as vike-react and vike-react-apollo powered by the same hooks you can use.
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.