3.1 KiB
3.1 KiB
GadgetId
Overview
GadgetId is a string-based identifier type used throughout the Gadget monorepo for all entity IDs. It replaces MongoDB's native ObjectId type with a simple, portable string that works consistently across all packages without requiring Mongoose or MongoDB-specific conversions.
Type Definition
// packages/api/src/lib/gadget-id.ts
export type GadgetId = string;
Why GadgetId?
- Consistency: All packages use the same ID type regardless of whether they use Mongoose
- Simplicity: No
createFromHexString()ortoHexString()conversions needed - Portability: Works seamlessly from backend to frontend to drone workers
- Type safety: Compile-time checking ensures IDs are always strings
Usage
Interfaces
Always use GadgetId for _id fields in interfaces:
import { GadgetId } from "@gadget/api";
interface IUser {
_id: GadgetId;
email: string;
displayName: string;
}
Mongoose Schemas
Use the following pattern for all schemas:
import { Schema, model } from "mongoose";
import { GadgetId } from "@gadget/api";
import { nanoid } from "nanoid";
const MySchema = new Schema<IMyInterface>({
_id: { type: String, default: () => nanoid() },
// ... other fields
});
Important Schema Rules
Do NOT add unique: true or required: true to the _id field:
- MongoDB automatically creates a unique index on
_id; specifyingunique: truecauses duplicate index errors at startup - MongoDB handles
_idvalidation automatically; specifyingrequired: truecauses save failures because the default is assigned AFTER validation
Correct:
_id: { type: String, default: () => nanoid() }
Incorrect:
// DON'T do this - breaks everything
_id: { type: String, default: () => nanoid(), unique: true, required: true }
Creating Documents
const thing = new Thing({ /* other fields */ });
await thing.save(); // Works - MongoDB handles _id automatically
Passing IDs to Functions
IDs are strings - just pass them directly:
const userId: GadgetId = user._id;
await userService.getById(userId); // No conversion needed
GadgetId vs ObjectId
| Operation | ObjectId | GadgetId |
|---|---|---|
| Type | ObjectId |
string |
| Creation | new ObjectId() |
nanoid() (via schema default) |
| String conversion | id.toHexString() |
Not needed |
| Parsing from string | createFromHexString(str) |
Not needed |
| Mongoose casting | Automatic with Schema.Types.ObjectId |
Automatic with type: String |
Importing GadgetId
// From @gadget/api (recommended for most code)
import { GadgetId } from "@gadget/api";
// From packages/api directly (for @gadget/api consumers)
import { GadgetId } from "../../../packages/api/dist/lib/gadget-id.js";
Rules
- Never use
ObjectIddirectly in application code - Never import
ObjectIdfrom Mongoose in service/controller code - Always use
GadgetIdfor_idfields in interfaces and function parameters - Never add
uniqueorrequiredto_idin Mongoose schemas