Noma

Astro

Astro

Use the JavaScript SDK in server-side Astro code: frontmatter in .astro pages (with prerender / output settings in mind), or endpoints for JSON APIs. Never put your personal access token in client-side scripts.

Install

npm install @nomacms/js-sdk

Environment variables

Use .env (and .env.production for deploys). Astro exposes private variables to the server only unless you prefix with PUBLIC_.

NOMA_PROJECT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
NOMA_API_KEY=noma_...

Reference them in server code via import.meta.env.NOMA_PROJECT_ID and import.meta.env.NOMA_API_KEY (environment variables).

Server-only client helper

// src/lib/noma.ts
import { createClient } from "@nomacms/js-sdk"
 
export function getNomaServerClient() {
  const projectId = import.meta.env.NOMA_PROJECT_ID
  const apiKey = import.meta.env.NOMA_API_KEY
 
  if (!projectId || !apiKey) {
    throw new Error("Missing NOMA_PROJECT_ID or NOMA_API_KEY")
  }
 
  return createClient({
    projectId,
    apiKey,
  })
}

Static generation: blog index

For content that can be baked at build time, fetch in page frontmatter. Set prerender appropriately for your adapter and hosting model.

---
// src/pages/posts/index.astro
import { getNomaServerClient } from "../lib/noma"
 
const noma = getNomaServerClient()
const result = await noma.content.list("posts", {
  state: "published",
  paginate: 24,
  sort: "created_at:desc",
})
const posts = "data" in result ? result.data : result
---
 
<ul>
  {posts.map((post) => (
    <li>
      <a href={`/posts/${post.uuid}/`}>{String(post.fields?.title ?? post.uuid)}</a>
    </li>
  ))}
</ul>

Rebuild or use on-demand regeneration when CMS content changes and you need updates without a full redeploy.

Dynamic paths: getStaticPaths

---
// src/pages/posts/[id].astro
import { getNomaServerClient } from "../../lib/noma"
 
export async function getStaticPaths() {
  const noma = getNomaServerClient()
  const result = await noma.content.list("posts", { state: "published", paginate: 500 })
  const posts = "data" in result ? result.data : result
  return posts.map((post) => ({
    params: { id: post.uuid },
  }))
}
 
const { id } = Astro.params
const noma = getNomaServerClient()
const post = await noma.content.get("posts", id!, { state: "published" })
---
 
<article>
  <h1>{String(post.fields?.title ?? "")}</h1>
</article>

Adjust pagination or use server rendering if you have more entries than you can list in one call.

JSON endpoints

// src/pages/api/posts.json.ts
import type { APIRoute } from "astro"
import { getNomaServerClient } from "../../lib/noma"
 
export const GET: APIRoute = async () => {
  const noma = getNomaServerClient()
  const data = await noma.content.list("posts", { state: "published", paginate: 20 })
  return new Response(JSON.stringify(data), {
    headers: { "Content-Type": "application/json" },
  })
}

Runtime

Run Noma requests in Node server contexts for best compatibility with the SDK’s HTTP stack. If you target edge runtimes, verify behavior in that environment.

End users (project auth)

Project Auth should run on the server: use Astro endpoints or your host’s serverless functions for sign-in and token refresh, and pass projectUserAuth only in server bundles—see Installation & Setup.

  • Next.js and Nuxt - Same SDK patterns on other frameworks.
  • Installation & Setup - Full client configuration.
  • Content API - Personal access tokens (per workspace) and project-id.
  • Quickstart - Create a project and test data in the dashboard.

Search documentation

Find guides and reference pages