Quickstart
Jumpstart your development with this Quickstart guide. Learn to seamlessly integrate Remult in various stacks, from installation to defining entities for efficient data querying and manipulation.
Experience Remult with an Interactive Tutorial
For a guided, hands-on experience, try our interactive online tutorial. It's the fastest way to get up and running with Remult and understand its powerful features.
Installation
The remult package is all you need for both frontend and backend code. If you're using one package.json
for both frontend and backend (or a meta-framework) - install Remult once in the project's root folder. If you're using multiple package.json
files (monorepo) - install Remult in both server and client folders.
npm install remult
yarn add remult
pnpm add remult
bun add remult
Server-side Initialization
Remult is initialized on the server-side as a request handling middleware, with a single line of code. Here is the code for setting up the Remult middleware:
import express from 'express'
import { remultExpress } from 'remult/remult-express'
const app = express()
app.use(remultExpress({}))
app.listen(3000)
import fastify from 'fastify'
import { remultFastify } from 'remult/remult-fastify'
(async () => {
const server = fastify()
await server.register(remultFastify({}))
server.listen({ port: 3000 })
})()
// src/app/api/[...remult]/route.ts
import { remultNextApp } from 'remult/remult-next'
export const api = remultNextApp({})
export const { GET, POST, PUT, DELETE } = api
// src/routes/api/[...remult]/+server.ts
import { remultSveltekit } from 'remult/remult-sveltekit'
export const _api = remultSveltekit({})
export const { GET, POST, PUT, DELETE } = _api
// server/api/[...remult].ts
import { remultNuxt } from 'remult/remult-nuxt'
export const api = remultNuxt({})
export default defineEventHandler(api)
// enable experimental decorators
// Add to nuxt.config.ts
nitro: {
esbuild: {
options: {
tsconfigRaw: {
compilerOptions: {
experimentalDecorators: true,
},
},
},
},
},
vite: {
esbuild: {
tsconfigRaw: {
compilerOptions: {
experimentalDecorators: true,
},
},
},
},
import { type Plugin, server } from '@hapi/hapi'
import { remultHapi } from 'remult/remult-hapi'
(async () => {
const hapi = server({ port: 3000 })
await hapi.register(remultHapi({}))
hapi.start()
})()
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { remultHono } from 'remult/remult-hono'
const app = new Hono()
const api = remultHono({})
app.route('', api)
serve(app)
// src/main.ts
import { remultExpress } from 'remult/remult-express'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.use(remultExpress({}))
await app.listen(3000)
}
bootstrap()
import * as koa from 'koa'
import * as bodyParser from 'koa-bodyparser'
import { createRemultServer } from 'remult/server'
const app = new koa()
app.use(bodyParser())
const api = createRemultServer({})
app.use(async (ctx, next) => {
const r = await api.handle(ctx.request)
if (r) {
ctx.response.body = r.data
ctx.response.status = r.statusCode
} else return await next()
})
app.listen(3000, () => {})
Connecting a Database
Use the dataProvider
property of Remult's server middleware to set up a database connection for Remult.
Recommended - Use default local JSON files and connect a database later
If the dataProvider
property is not set, Remult stores data as JSON files under the ./db
folder.
Here are examples of connecting to some commonly used back-end databases:
Install node-postgres:
npm i pg
Set the dataProvider
property:
import express from "express"
import { remultExpress } from "remult/remult-express"
import { createPostgresDataProvider } from "remult/postgres"
const app = express()
const connectionString = "postgres://user:password@host:5432/database"
app.use(
remultExpress({
dataProvider:
createPostgresDataProvider({
connectionString, // default: process.env["DATABASE_URL"]
// configuration: {} // optional = a `pg.PoolConfig` object or "heroku"
})
})
)
Or use your existing postgres connection
import { Pool } from 'pg'
import { SqlDatabase } from 'remult'
import { PostgresDataProvider } from 'remult/postgres'
import { remultExpress } from 'remult/remult-express'
const pg = new Pool({
connectionString: '....',
})
const app = express()
app.use(
remultExpress({
dataProvider: new SqlDatabase(new PostgresDataProvider(pg)),
}),
)
Integrate Auth
Remult is completely unopinionated when it comes to user authentication. You are free to use any kind of authentication mechanism, and only required to provide Remult with a getUser
function that extracts a user object (which implements the minimal Remult UserInfo
interface) from a request.
Here are examples of integrating some commonly used auth providers:
import express from 'express'
import session from 'express-session'
import { remultExpress } from 'remult/remult-express'
const app = express()
app.use(
session({
/* ... */
}),
)
app.post('/api/signIn', (req, res) => {
req.session!['user'] = { id: 1, name: 'admin', roles: ['admin'] }
})
app.use(
remultExpress({
getUser: (req) => req.session!['user'],
}),
)
// src/app/api/[...remult]/route.ts
import { remultNextApp } from 'remult/remult-next'
import { getServerSession } from 'next-auth'
import { authOptions } from '../auth/[...nextauth]/route'
export const api = remultNextApp({
getUser: async () => {
const user = (await getServerSession(authOptions))?.user
return user?.email && user?.name
? { id: user?.email, name: user?.name }
: undefined
},
})
export const { POST, PUT, DELETE, GET, withRemult } = api
Defining and Serving an Entity
Remult entity classes are shared between frontend and backend code.
// shared/product.ts
import { Entity, Fields } from 'remult'
@Entity('products', {
allowApiCrud: true,
allowApiDelete: 'admin',
})
export class Product {
@Fields.uuid()
id!: string
@Fields.string()
name = ''
@Fields.number()
unitPrice = 0
}
Alternatively, generate entities from an existing Postgres database.
Serve Entity CRUD API
All Remult server middleware options contain an entities
array. Use it to register your Entity.
// backend/index.ts
app.use(
remultExpress({
entities: [Product],
}),
)
Using your Entity on the Client
To start querying and mutating data from the client-side using Remult, use the remult.repo
function to create a Repository
object for your entity class. This approach simplifies data operations, allowing you to interact with your backend with the assurance of type safety.
// frontend/code.ts
import { remult } from 'remult'
import { Product } from '../shared/product'
const productsRepo = remult.repo(Product)
async function playWithRemult() {
// add a new product to the backend database
await productsRepo.insert({ name: 'Tofu', unitPrice: 5 })
// fetch products from backend database
const products = await productsRepo.find({
where: { unitPrice: { '>=': 5 } },
orderBy: { name: 'asc' },
limit: 10,
})
console.log(products)
// update product data
const tofu = products.filter((p) => p.name === 'Tofu')
await productsRepo.save({ ...tofu, unitPrice: tofu.unitPrice + 5 })
// delete product
await productsRepo.delete(tofu)
}
playWithRemult()
Client-side Customization
Recommended Defaults
By default, remult uses the browser's fetch API, and makes data API calls using the base URL /api
(same-origin).
Changing the default API base URL
To use a different origin or base URL for API calls, set the remult object's apiClient.url
property.
remult.apiClient.url = 'http://localhost:3002/api'
Using an alternative HTTP client
Set the remult
object's apiClient.httpClient
property to customize the HTTP client used by Remult:
import axios from 'axios'
import { remult } from 'remult'
remult.apiClient.httpClient = axios
//...
import { HttpClientModule, HttpClient } from '@angular/common/http'
import { remult } from 'remult'
@NgModule({
//...
imports: [
//...
HttpClientModule,
],
})
export class AppModule {
constructor(http: HttpClient) {
remult.apiClient.httpClient = http
}
}