Add files to your Postgres branches via Neon Object Storage, our S3-compatible object store
/APIs & SDKs/Migrate to @neon/sdk

Migrate from @neondatabase/api-client to @neon/sdk

Move Platform API automation from the legacy Axios client to the official fetch-based SDK

@neondatabase/api-client still works

The legacy @neondatabase/api-client package continues to work. @neon/sdk is the recommended replacement for new projects and for teams that want fetch-based, zero-dependency Platform API access with ergonomic workflows.

This guide maps common @neondatabase/api-client patterns to @neon/sdk. For full method reference, see the Neon Management SDK documentation.

What changes

@neondatabase/api-client@neon/sdk
HTTP clientAxiosfetch (zero runtime dependencies)
FactorycreateApiClient({ apiKey })createNeonClient({ apiKey })
Method layoutFlat (listProjects, createProjectBranch, …)Namespaced (neon.projects.list(), neon.branches.create(), …)
Success pathresponse.data on Axios responses{ data, error } by default, or bare resource with throwOnError: true
ErrorsAxiosError + error.responseTyped NeonError hierarchy (kind: api, not_found, auth, …)
Node.jsBroader support≥ 20.19 (or any runtime with global fetch)
Low-level APIGenerated methods on the clientraw.* functions + neon.client

Install and swap the package

npm uninstall @neondatabase/api-client
npm install @neon/sdk

Update imports:

// Before
import { createApiClient } from '@neondatabase/api-client';

// After
import { createNeonClient } from '@neon/sdk';

Client setup

// Before
const apiClient = createApiClient({
  apiKey: process.env.NEON_API_KEY!,
});

// After — check { data, error } on each call
const neon = createNeonClient({
  apiKey: process.env.NEON_API_KEY!,
});

// After — throw on error (closer to try/catch style)
const neon = createNeonClient({
  apiKey: process.env.NEON_API_KEY!,
  throwOnError: true,
});

createNeonClient also supports orgId, waitForReadiness, retries, baseUrl, and a custom fetch implementation. See Neon Management SDK.

Method mapping

Common Platform API calls and their @neon/sdk equivalents:

@neondatabase/api-client@neon/sdk
getCurrentUserOrganizations()neon.user.organizations()
getCurrentUserInfo()neon.user.me()
listProjects({ org_id })neon.projects.list({ org_id }).page() or .all()
createProject({ project })neon.projects.create({ name, region_id, … })
getProject(projectId)neon.projects.get(projectId)
deleteProject(projectId)neon.projects.delete(projectId)
listProjectBranches({ projectId })neon.branches.list(projectId).page() or .all()
createProjectBranch(projectId, body)neon.branches.create(projectId, input) or neon.branches.createWithCompute(…)
getConnectionUri(projectId, query)neon.postgres.connectionString({ projectId, … })
listProjectBranchDatabases(…)neon.postgres.databases.list(…)
createProjectBranchDatabase(…)neon.postgres.databases.create(…)
listProjectBranchRoles(…)neon.postgres.roles.list(…)
createProjectBranchRole(…)neon.postgres.roles.create(…)
listProjectEndpoints(projectId)neon.postgres.endpoints.list(projectId)
listApiKeys()neon.apiKeys.list()
getActiveRegions()neon.regions.list()

Endpoints that are not wrapped in an ergonomic namespace remain available through raw.

Error handling

Before — Axios throws; inspect error.response:

try {
  const response = await apiClient.getProject(projectId);
  console.log(response.data.project);
} catch (error) {
  // AxiosError — error.response?.status, error.response?.data
}

After — default { data, error } envelope:

const { data: project, error } = await neon.projects.get(projectId);
if (error) {
  if (error.kind === 'not_found') {
    // handle 404
  }
  throw error;
}
console.log(project);

AfterthrowOnError: true on the client or per call:

const neon = createNeonClient({ apiKey, throwOnError: true });
const project = await neon.projects.get(projectId); // throws NeonError on failure

Side-by-side examples

List projects

// Before
const orgs = await apiClient.getCurrentUserOrganizations();
const orgId = orgs.data.organizations[0].id;
const response = await apiClient.listProjects({ org_id: orgId });
console.log(response.data.projects);

// After
const { data: orgs, error: orgsError } = await neon.user.organizations();
if (orgsError) throw orgsError;

const { data: page, error } = await neon.projects.list({ org_id: orgs[0].id }).page();
if (error) throw error;
console.log(page.items);

Create a project with a connection string

// Before
const response = await apiClient.createProject({
  project: { name: 'my-app', region_id: 'aws-us-east-1', pg_version: 17 },
});
const uri = response.data.connection_uris[0].connection_uri;

// After — waits for provisioning and returns a ready connection string
const { data, error } = await neon.projects.createAndConnect({
  name: 'my-app',
  region_id: 'aws-us-east-1',
  pg_version: 17,
});
if (error) throw error;
const { project, connectionString } = data;

Create a branch with compute

// Before
import { EndpointType } from '@neondatabase/api-client';

await apiClient.createProjectBranch(projectId, {
  branch: { name: 'dev-1', parent_id: parentBranchId },
  endpoints: [{ type: EndpointType.ReadWrite }],
});

// After
const { data, error } = await neon.branches.createWithCompute(projectId, {
  name: 'dev-1',
  parentId: parentBranchId,
});
if (error) throw error;
const { branch, endpoint, connectionString } = data;

Create a database

// Before
await apiClient.createProjectBranchDatabase(projectId, branchId, {
  database: { name: 'mydb', owner_name: 'neondb_owner' },
});

// After
const { error } = await neon.postgres.databases.create(projectId, branchId, {
  name: 'mydb',
  owner_name: 'neondb_owner',
});
if (error) throw error;

Raw layer changes in 1.0

If you adopted @neon/sdk 0.x and used raw.* directly, 1.0 changes the raw contract:

0.x1.0
hey-api { data, request, response } envelope{ data, error } NeonResult
responseStyle: "data"Removed
throwOnError: true needed workaroundsReturns the bare resource; types narrow correctly
// Before (0.x)
const project = await raw.getProject({
  client: neon.client,
  path: { project_id: projectId },
  throwOnError: true,
  responseStyle: 'data',
});

// After (1.0)
const project = await raw.getProject({
  client: neon.client,
  path: { project_id: projectId },
  throwOnError: true,
});

Drop any unwrapRaw helpers or responseStyle usage.

Types

Import request/response types from @neon/sdk instead of @neondatabase/api-client:

import type { Project, Branch } from '@neon/sdk';

Some generated type names changed (for example, DataAPI*DataApi*). Endpoint types are string unions ("read_write" / "read_only") rather than enums.

What you gain

  • Workflow helpers such as projects.createAndConnect and branches.createWithCompute that poll operations and return connection strings
  • Readiness polling via waitForReadiness and neon.operations.waitFor
  • Automatic retries on safe statuses (423, 429, 503)
  • Ergonomic beta APIs for storage, functions, credentials, AI gateway, snapshots, and branch-scoped Managed Better Auth (neon.auth, neon.storage, …)
  • Tree-shakeable raw imports from @neon/sdk/raw

Next steps

Need help?

Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.

Was this page helpful?
Edit on GitHub