Every app re-implements the same plumbing: signing a token, hashing a password, generating a sitemap, formatting money, debouncing an input. Lacspace packaged those, once, properly — and gave them away. The result is 100+ published npm packages (plus two CLIs), each doing one job well.

Thirteen kits, grouped by the job

The 13 Lacspace kits: Core SDK, SEO, Security, React, MailKit, StockKit, WebKit, App, Utils, Data, DX, Backend
Pick a kit for the job in front of you.
  • Core SDK — talk to the Lacspace platform from any JS runtime (api, auth, analytics).
  • SEO Kit — every file and tag crawlers and AI read: metadata, JSON-LD, sitemap, robots, RSS, llms.txt.
  • Security Kit — vetted primitives on Web Crypto: crypto, password, jwt, apikey, otp, webauthn, mfa, lock, headers, redact.
  • React Kit — hooks, tiny state, data fetching and UX.
  • MailKit — send, compose and validate email.
  • App / Web / Utils / Data / DX / Backend Kits — validation, forms, OG images, config, rate-limiting, IDs, retries, xlsx/csv, humanize, colour, signed URLs, PDFs.

What they have in common

  • Zero third-party dependencies — tiny installs, no transitive bloat.
  • Isomorphic — Node, edge and browser from the same import.
  • Dual ESM + CJS — import or require, your call.
  • TypeScript-first — types in the box.
  • Actively versioned — regularly upgraded (the create-lacspace-app scaffolder alone is on v2.13).

Start here

Browse everything at lacspace.com/packages, read per-package docs at lacspace.com/docs (there’s a downloadable handbook PDF), or scaffold a whole app in one command with create-lacspace-app.

How installing and importing works

Every package lives under the @lacspace scope and is installed on its own, so you only pay for what you use. Each ships an exports map with separate ESM and CommonJS builds and bundled type definitions, which is what makes both import and require work without extra configuration.

npm i @lacspace/validate @lacspace/money   # or pnpm add / yarn add / bun add
// ESM (Next.js, Vite, modern Node)
import { v } from '@lacspace/validate';

// CommonJS (older Node services)
const { money } = require('@lacspace/money');

A few packages build on a sibling rather than a third party. For example, @lacspace/password and @lacspace/jwt use @lacspace/crypto, and @lacspace/sdk bundles @lacspace/api, @lacspace/auth and @lacspace/analytics. Nothing outside the scope is pulled in.

A taste of each kit

One short example per area, using the real exports documented in each package's README.

SEO Kit

import { seoMetadata } from '@lacspace/seo';

export const metadata = seoMetadata({
  title: 'Pricing', description: 'Simple, transparent plans.',
  canonical: '/pricing', baseUrl: 'https://example.com',
}); // a Next.js App Router Metadata object

Security Kit

import { sign, verify } from '@lacspace/jwt';

const token = await sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: 3600 });
const claims = await verify(token, process.env.JWT_SECRET); // throws JwtError with a code

React Kit

import { create } from '@lacspace/store';

const useCounter = create((set) => ({ count: 0, inc: () => set((s) => ({ count: s.count + 1 })) }));
const count = useCounter((s) => s.count); // no provider needed

MailKit

import { createMailer, presets } from '@lacspace/mailer';
import { otpEmail } from '@lacspace/email-templates';

const mail = createMailer(presets.gmail({ user, pass }));
await mail.send({ to, subject: 'Your code', html: otpEmail({ code: '482913' }) });

App and Web Kits

import { createEnv, url, port } from '@lacspace/env';
import { rateLimit } from '@lacspace/rate-limit';

export const env = createEnv({ DATABASE_URL: url(), PORT: port({ default: 3000 }) });
const limiter = rateLimit({ limit: 10, windowMs: 60_000 });
const { success } = await limiter.check(ip);

Utils, Data, DX and Backend Kits

import { uuidv7 } from '@lacspace/id';
import { jsonToXlsx } from '@lacspace/xlsx';
import { bytes } from '@lacspace/humanize';
import { invoice } from '@lacspace/pdf';

uuidv7();                 // time-sortable UUID
jsonToXlsx(rows);         // .xlsx bytes, no dependencies
bytes(1536);              // "1.5 KB"
invoice({ brand: 'Acme', number: 'INV-1', date: '2026-08-23',
  items: [{ description: 'Work', quantity: 1, rate: 100 }] }); // PDF bytes, no browser

Choosing packages for a new project

A practical way to adopt the ecosystem is to start from the jobs every app has, then add kits as the product grows:

  • Day one: @lacspace/env to fail fast on bad configuration, @lacspace/validate for request bodies, and @lacspace/seo for metadata and JSON-LD.
  • Accounts: @lacspace/password, @lacspace/jwt and @lacspace/lock for sign-in, with @lacspace/otp or @lacspace/webauthn when you add a second factor.
  • Front end: @lacspace/hooks, @lacspace/store and @lacspace/query for the React layer, @lacspace/form for server actions with a honeypot.
  • Operations: @lacspace/rate-limit, @lacspace/retry, @lacspace/webhooks and @lacspace/idempotency once real traffic and integrations arrive.
  • Reporting: @lacspace/xlsx, @lacspace/csv and @lacspace/pdf for exports, and @lacspace/money anywhere amounts are stored or summed.

Because each package is independent, you can adopt one without committing to the rest, and replace one later without untangling a shared framework.

Things to keep in mind

  • A few packages are server-only by design. @lacspace/mailer and @lacspace/email-verify open TCP sockets through Node's built-in modules, so they need Node 18+ and do not run in browsers. Their READMEs say so explicitly.
  • React packages use React as a peer dependency (React 18 or newer) rather than bundling it.
  • In-memory defaults are per process. Rate limits, lockouts and idempotency records default to memory; each of those packages defines a small store interface for Redis or a database when you run several instances.
  • Upgrades are additive. The READMEs list what each minor release added and state that existing exports are unchanged, so upgrading within a major version is meant to be safe.

Where to learn more

The free packages are released under the Lacspace Free Licence v1.0, a permissive licence that allows personal and commercial use at no cost provided the notice is kept.

Frequently asked questions

What is the @lacspace package ecosystem?

A suite of 100+ published npm packages (plus the create-lacspace-app and create-lacspace-seo CLIs) that cover the things every app re-implements — SDK, SEO, security, React, email, data, dev-experience and more. They are zero-dependency, isomorphic TypeScript, shipped as dual ESM + CJS, and grouped into 13 kits.

Are the packages really zero-dependency?

Yes — no third-party dependencies. Most packages have an empty dependency tree; a few compose from sibling @lacspace packages (for example @lacspace/jwt uses @lacspace/crypto), but nothing pulls in outside code. That means tiny installs and no transitive supply-chain risk.

Which runtimes do they support?

They are isomorphic: the same import runs on Node, on the edge (Vercel/Cloudflare workers) and in the browser, built on Web-standard APIs. Crypto uses the Web Crypto API — never hand-rolled.

How are the packages organised?

Into 13 kits by job: Core SDK, SEO Kit, Security Kit, React Kit, MailKit, StockKit, WebKit, App Kit, Utils Kit, Data Kit, DX Kit, Backend Kit and a Nepal toolkit. Browse them at lacspace.com/packages with per-package docs at lacspace.com/docs.

What licence are they under?

The Lacspace Free Licence (MIT-equivalent) for the free tier — free for personal and commercial use. Some packages are commercial/client/private; each package page states its tier.