Skip to main content
PocketBase comes with a built-in JavaScript VM that allows you to extend your backend with custom JavaScript code. You can write hooks, custom routes, scheduled tasks, and more using JavaScript.

What is the JavaScript VM?

The JavaScript VM (JSVM) is a plugin that enables you to write server-side JavaScript code that runs directly in PocketBase. It uses the goja JavaScript runtime, which implements ECMAScript 5.1 with some ES6+ features.

Getting started

To use JavaScript hooks in PocketBase, you need to:
  1. Create a pb_hooks directory in your project root
  2. Add .pb.js or .pb.ts files to this directory
  3. Write your JavaScript code using the PocketBase APIs
Files must end with .pb.js or .pb.ts to be recognized by the JavaScript VM. The .pb.ts extension is recommended for better IDE support with TypeScript definitions.

Basic example

Here’s a simple example that adds a custom route:
// pb_hooks/routes.pb.js

routerAdd("GET", "/hello", (e) => {
  return e.json(200, { "message": "Hello from PocketBase!" })
})

File structure

Your PocketBase project structure should look like this:
my-project/
├── pb_data/           # Database and storage
├── pb_hooks/          # JavaScript hooks (your custom code)
│   ├── main.pb.js
│   ├── routes.pb.js
│   └── tasks.pb.js
├── pb_migrations/     # Database migrations
└── pocketbase         # PocketBase executable

Available APIs

The JavaScript VM provides several namespaces and functions:

Global variables

  • $app - The PocketBase application instance
  • $template - Template rendering helpers
  • __hooks - Absolute path to the hooks directory

Utility namespaces

  • $http - HTTP client for making requests
  • $security - Cryptography and security utilities
  • $filesystem - File system operations
  • $os - Operating system utilities
  • $filepath - File path utilities
  • $dbx - Database query builder helpers
  • $apis - API route helpers and middlewares
  • $mails - Email sending utilities

Global functions

  • routerAdd() - Register custom HTTP routes
  • routerUse() - Register global middlewares
  • cronAdd() - Schedule cron jobs
  • cronRemove() - Remove cron jobs
  • on*() - Event hooks (e.g., onRecordCreate, onRecordUpdate)

TypeScript support

PocketBase automatically generates a types.d.ts file in your pb_data directory with full TypeScript definitions. To use it:
  1. Create your hook files with .pb.ts extension
  2. Add a reference directive at the top of your file:
/// <reference path="../pb_data/types.d.ts" />

routerAdd("GET", "/users/:id", (e) => {
  const id = e.request.pathValue("id")
  // Your IDE will now provide autocomplete and type checking
  return e.json(200, { id })
})

Hot reloading

During development, you can enable hot reloading to automatically restart PocketBase when your hook files change:
./pocketbase serve --hooksWatch=true
Hot reloading is not supported on Windows. You’ll need to manually restart PocketBase after making changes.

Performance

The JavaScript VM uses a pool of runtime instances to handle concurrent requests efficiently. You can configure the pool size:
./pocketbase serve --hooksPool=25
The default pool size is 15 instances.

Node.js compatibility

The JavaScript VM includes support for some Node.js modules:
  • console - Logging to stdout
  • require() - Module loading
  • process - Process information
  • buffer - Buffer operations
You can use require() to load local modules or packages from node_modules.

Error handling

Errors in JavaScript hooks are automatically caught and returned as HTTP errors. You can throw errors or return them:
routerAdd("POST", "/api/validate", (e) => {
  const data = e.requestInfo().data
  
  if (!data.email) {
    throw new BadRequestError("Email is required")
  }
  
  return e.json(200, { success: true })
})

Next steps

App instance

Learn about the global $app instance and its methods

Collections

Work with collections and schemas

Records

Create, read, update, and delete records

Events

Hook into PocketBase lifecycle events