Keywords: resource, entity, function, agent, connector, push, readAll, deploy, site, tar.gz, deployAll, ProjectData
Resources are project-specific collections (entities, functions, agents, connectors) that can be read from the filesystem and pushed to the Base44 API.
Defined in packages/cli/src/resources/types.ts:
export interface Resource<T> {
readAll: (dir: string) => Promise<T[]>;
push: (items: T[]) => Promise<unknown>;
}The push method handles empty arrays gracefully (returns early without making an API call).
Each resource follows a consistent file structure inside packages/cli/src/core/resources/<name>/:
<name>/
├── schema.ts # Zod schemas for validation
├── config.ts # File reading logic (reads from filesystem)
├── resource.ts # Resource<T> implementation
├── api.ts # API calls (push to server)
└── index.ts # Barrel exports
Example implementation:
// resources/<name>/resource.ts
export const entityResource: Resource<Entity> = {
readAll: readAllEntities,
push: pushEntities,
};- Create folder:
packages/cli/src/core/resources/<name>/ - Add
schema.tswith Zod schemas - Add
config.tswith file reading logic - Add
resource.tsimplementingResource<T> - Add
api.tsfor API calls - Add
index.tsbarrel exports - Update
packages/cli/src/core/resources/index.tsto export the new resource - Register in
packages/cli/src/core/project/config.ts(add toreadProjectConfig) - Add typed field to
ProjectDatainterface
Functions are read from the project's functions directory (e.g. base44/functions/ or path from config.jsonc). Two discovery modes:
Config-based: A folder that contains function.jsonc (or function.json) is a function. The config defines name, entry (path to the handler file), and optional automations. The config file can live at any depth under the functions dir (e.g. functions/foo/bar/function.jsonc). All *.js, *.ts, and *.json files in that folder and subfolders are included when deploying.
Zero-config: A folder that contains entry.js or entry.ts and has no function.jsonc in the same folder is also a function. The function name is the path from the functions root to that folder (e.g. functions/foo/bar/hello/entry.ts → name foo/bar/hello). File collection is recursive: all **/*.{js,ts,json} under that folder are included.
If both exist in the same folder (e.g. function.jsonc and entry.ts), the config wins: the function is loaded from the config and the name/entry come from the config file. Duplicate function names (same path or same config name) cause an error.
The site module at packages/cli/src/core/site/ handles deploying built frontend files. It follows a different pattern than resources:
- Reads built artifacts (JS, CSS, HTML) from the output directory
- Gets configuration from
site.outputDirectoryin project config - Creates a tar.gz archive and uploads it via
POST /api/apps/{app_id}/deploy-dist
import { deploySite } from "@/core/site/index.js";
const { appUrl } = await deploySite("./dist");- Validate output directory exists and has files
- Create temporary tar.gz archive using
tarpackage - Upload archive to the API
- Parse response with Zod schema
- Clean up temporary archive file
The base44 deploy command deploys all project resources in one operation:
import { deployAll, hasResourcesToDeploy } from "@/core/project/index.js";
if (!hasResourcesToDeploy(projectData)) {
return;
}
const { appUrl } = await deployAll(projectData);What it deploys (in order):
- Entities (via
entityResource.push()) - Functions (via
functionResource.push()) - Agents (via
agentResource.push()) - Connectors (via
pushConnectors()) -- may return OAuth redirect URLs - Site (if
site.outputDirectoryis configured)
base44 deploy # With confirmation prompt
base44 deploy -y # Skip confirmation
base44 deploy --yes # Skip confirmation