Skip to content
Schedule Social Media

Press Esc to close.

Breaking Bluesky Severity: low

@atproto/api 0.14: stricter types, $type required in records, is* helpers no longer cast

Announced13 Feb 2025
Effective13 Feb 2025
StatusIn effect

What changed

On February 13, 2025 Bluesky released version 0.14 of the @atproto/api TypeScript SDK. Generated interfaces now declare $type explicitly (optional on objects, required on records, and required inside open unions such as a post's embed via the new $Typed helper). The is* helpers no longer type-cast their input, validate* returns a precise type, a new asPredicate turns a validator into a type guard, and the [k: string]: unknown index signature was removed so typos in field names are caught.

What it means

TypeScript tools that build Bluesky posts with @atproto/api may get new compile errors on upgrade, because union members such as embeds need an explicit $type and is* helpers no longer narrow types unsafely.

Who is affected

Developers of Bluesky posting, scheduling and bot tools written in TypeScript with @atproto/api.

What to do by 13 Feb 2025

When upgrading to 0.14, add $type to embeds and other union values (use $Typed where required), switch to validate* or asPredicate where data is untrusted, mark intentional extra fields, and pin all @atproto packages to one version.

What this means for you

In February 2025 Bluesky made its free code toolkit stricter about the shape of a post. Apps that are updated now catch mistakes, like a video attached the wrong way, before the post is sent. You do not need to do anything. App makers may need a short round of fixes when they update.

The details

  • Explicit $type: generated interfaces now include $type, for example $type?: 'app.bsky.embed.video'. It is optional on plain objects and required on interfaces generated from record definitions.
  • Open unions: a post's embed is now typed as $Typed<AppBskyEmbedImages.Main> | $Typed<AppBskyEmbedVideo.Main> | ..., so an embed without $type is a type error.
  • is* helpers: they no longer cast based only on $type, and the old check that accepted a #main suffix was invalid under the spec. The post says they remain fine for data returned by Bluesky's APIs, which is "guaranteed" valid.
  • validate* and asPredicate: validate* now returns a typed value on success; asPredicate(validateX) turns it into a type guard for untrusted data.
  • No index signature: [k: string]: unknown was removed, so a typo such as atl instead of alt is caught. Mark intentional extra fields explicitly.
  • Dependencies: do not mix versions of @atproto/* packages; pin them with overrides or resolutions.
  • Source note: the post was on docs.bsky.app, which now redirects to bsky.network and no longer serves it. The text is in Bluesky's own bluesky-social/bsky-docs repository.
  • Later: in 2026 the packages moved to ESM and dropped Node 18 and 20; see TypeScript SDK upgrades.

What to do next

  • Business owners: Nothing.
  • Marketers and agencies: Nothing.
  • Developers: Upgrade in a branch, fix $type and $Typed errors on embeds and other union fields, use validate* for untrusted input, and pin one version of every @atproto/* package.

Primary sources

Checked against the source 7 Nov 2026

Get an email when a new API change is added

Follow new entries with the RSS feed. Each platform also has its own feed, for example X or Meta.