Overview
The @budgetbee/core package is the heart of BudgetBee, providing essential functionality for authentication, database access, feature flags, and core business logic.
Installation
pnpm add @budgetbee/core --filter your-package
Or in your package.json:
{
"dependencies" : {
"@budgetbee/core" : "workspace:*"
}
}
{
"name" : "@budgetbee/core" ,
"version" : "1.0.0" ,
"type" : "module" ,
"description" : "Core package for budgetbee"
}
Exports
The package provides multiple entry points:
// Authentication (server-side)
import { auth } from "@budgetbee/core/auth" ;
// Authentication (client-side)
import { authClient } from "@budgetbee/core/auth-client" ;
// Database access
import { db , getDb } from "@budgetbee/core/db" ;
import { getAuthAdminClient } from "@budgetbee/core/db-pool" ;
// Feature flags
import { getFeatureFlag } from "@budgetbee/core/feature-flags" ;
// Error handling
import { CustomError } from "@budgetbee/core/error" ;
// UI components
import { Component } from "@budgetbee/core/ui/component" ;
Authentication
Server-Side Auth
BudgetBee uses Better Auth for authentication with several plugins:
import { auth } from "@budgetbee/core/auth" ;
// Get current session
const session = await auth . api . getSession ({
headers: request . headers
});
// Verify user is authenticated
if ( ! session ?. user ) {
throw new Error ( 'Unauthorized' );
}
Configuration
The auth system is configured with:
Email & Password authentication
Email verification required
Organization support for multi-tenant features
JWT tokens for API access
Polar integration for subscription management
Role-based access control (RBAC)
Plugins
import {
bearer , // Bearer token authentication
customSession , // Custom session fields
jwt , // JWT token support
organization // Organization management
} from "better-auth/plugins" ;
Client-Side Auth
import { authClient } from "@budgetbee/core/auth-client" ;
// Sign in
const { data , error } = await authClient . signIn . email ({
email: '[email protected] ' ,
password: 'password'
});
// Sign out
await authClient . signOut ();
// Get current user
const { data : session } = await authClient . getSession ();
// Get access token
const { data : token } = await authClient . token ();
Email Verification
Email verification is required and handled automatically:
// Verification email is sent on signup
// Uses @budgetbee/email package with Resend
email : {
enabled : true ,
requireEmailVerification : true ,
sendVerificationEmail : async ( data ) => {
// Sends email via Resend
}
}
Password Reset
// Request password reset
await authClient . forgetPassword ({
email: '[email protected] ' ,
redirectTo: '/reset-password'
});
// Reset password with token
await authClient . resetPassword ({
newPassword: 'newpassword' ,
token: 'reset-token'
});
Database Access
PostgREST Client
BudgetBee uses PostgREST for database access via REST API:
import { db , getDb } from "@budgetbee/core/db" ;
// With existing token
const client = db ( token );
// Automatically fetch token
const client = await getDb ();
// Query database
const { data , error } = await client
. from ( 'transactions' )
. select ( '*' )
. eq ( 'user_id' , userId )
. order ( 'date' , { ascending: false })
. limit ( 10 );
Query Examples
// Get all transactions
const { data } = await client
. from ( 'transactions' )
. select ( '*' );
// Select specific columns
const { data } = await client
. from ( 'transactions' )
. select ( 'id, amount, description' );
// Join with categories
const { data } = await client
. from ( 'transactions' )
. select ( `
*,
category:categories(*)
` );
Admin Database Access
For operations requiring elevated privileges:
import {
getAuthAdminClient ,
getSubscriptionAdminClient
} from "@budgetbee/core/db-pool" ;
// Auth operations (users, sessions)
const authClient = getAuthAdminClient ();
const result = await authClient . query (
'SELECT * FROM users WHERE id = $1' ,
[ userId ]
);
// Subscription operations
const subClient = getSubscriptionAdminClient ();
const result = await subClient . query (
'UPDATE subscriptions SET status = $1 WHERE id = $2' ,
[ 'active' , subscriptionId ]
);
Use admin clients carefully - They bypass row-level security. Only use for privileged operations.
Feature Flags
BudgetBee includes a flexible feature flag system with multi-level scoping:
import { getFeatureFlag } from "@budgetbee/core/feature-flags" ;
import type { FeatureFlagScope } from "@budgetbee/core/feature-flags" ;
// Check global feature flag
const isEnabled = await getFeatureFlag ( 'new-dashboard' );
// Check account-specific flag
const isEnabled = await getFeatureFlag ( 'beta-features' , {
accountId: user . id
});
// Check organization-specific flag
const isEnabled = await getFeatureFlag ( 'custom-branding' , {
orgId: organization . id
});
// Check with full context
const isEnabled = await getFeatureFlag ( 'advanced-analytics' , {
accountId: user . id ,
orgId: organization . id
});
Feature Flag Scopes
Scope Priority Organization > Account > Global
Feature flags can be scoped at three levels:
Global - Applies to all users
Account - Specific to individual user accounts
Organization - Specific to organizations
Caching
Feature flags are cached in Redis for 5 minutes:
// Cache key format
const cacheKey = `flag: ${ key } :org: ${ orgId } :acc: ${ accountId } ` ;
// TTL: 300 seconds (5 minutes)
await redis . setex ( cacheKey , 300 , String ( value ));
Permissions
BudgetBee implements role-based access control:
import {
accessControl ,
owner ,
admin ,
editor ,
viewer
} from "@budgetbee/core/permissions" ;
Role Hierarchy
Owner
Full access to organization, can manage all members and settings
Admin
Can manage organization settings and members (except owner)
Editor
Can create and edit content, limited administrative access
Viewer
Read-only access to organization data
UI Components
The core package includes some UI components for auth flows:
import { SignInForm } from "@budgetbee/core/ui/sign-in-form" ;
import { SignUpForm } from "@budgetbee/core/ui/sign-up-form" ;
For general UI components, use @budgetbee/ui instead.
Dependencies
Key dependencies used by @budgetbee/core:
{
"dependencies" : {
"@budgetbee/billing" : "workspace:*" ,
"@budgetbee/email" : "workspace:*" ,
"@polar-sh/better-auth" : "1.6.4" ,
"@supabase/postgrest-js" : "^1.21.4" ,
"better-auth" : "1.4.17" ,
"ioredis" : "^5.8.2" ,
"zod" : "^4.3.6"
}
}
Environment Variables
Required environment variables:
# Database
POSTGRES_USER = your_db_user
POSTGRES_PASSWORD = your_db_password
POSTGRES_HOST = localhost
POSTGRES_PORT = 5432
POSTGRES_DB = budgetbee
# Admin Users
POSTGRES_AUTH_ADMIN_USER = auth_admin
POSTGRES_AUTH_ADMIN_PASSWORD = password
POSTGRES_SUBSCRIPTION_ADMIN_USER = sub_admin
POSTGRES_SUBSCRIPTION_ADMIN_PASSWORD = password
# PostgREST
NEXT_PUBLIC_PG_REST_URL = http://localhost:3000
PGRST_JWT_SECRET = your_jwks_secret
# Redis
REDIS_URL = redis://localhost:6379
# Application
NEXT_PUBLIC_APP_URL = http://localhost:3001
NEXT_PUBLIC_SITE_URL = http://localhost:3000
# Email (Resend)
RESEND_API_KEY = your_resend_api_key
SMTP_SENDER_NAME = BudgetBee
SMTP_MAIL = [email protected]
# Polar
POLAR_ACCESS_TOKEN = your_polar_token
Database Migrations
Migrations are stored in packages/core/migrations/:
packages/core/migrations/
├── better-auth-migrations.sql # Auth tables
├── init.sql # Initial schema
├── migration_2024_01_15_ * .sql # Feature migrations
└── migration_2024_02_01_ * .sql # More migrations
Run migrations in order:
Or manually:
./scripts/run_migrations.sh
Redis Configuration
Redis is used for caching and session storage:
import { redis } from "@budgetbee/core/redis" ;
// Get value
const value = await redis . get ( key );
// Set with expiration
await redis . setex ( key , 300 , value );
// Delete
await redis . del ( key );
Best Practices
Use getDb() Prefer getDb() over db() to automatically handle token management
Check Permissions Always verify user permissions before performing sensitive operations
Cache Feature Flags Feature flags are automatically cached, don’t implement additional caching
Handle Errors Always handle errors from database operations and auth calls
Troubleshooting
Database connection fails
Check environment variables:
echo $NEXT_PUBLIC_PG_REST_URL
echo $PGRST_JWT_SECRET
Ensure PostgREST is running:
cd infra
docker compose ps
Authentication not working
Verify JWKS secret is set:
Visit http://localhost:3000/api/auth/jwks
Copy the secret
Set PGRST_JWT_SECRET in .env
Restart containers
Feature flags not updating
Feature flags are cached for 5 minutes. Either:
Wait for cache to expire
Flush Redis: redis-cli FLUSHDB
Next Steps
UI Package Explore the UI component library
Billing Package Learn about subscription management