Skip to content
← Back to activity

Solution skill

Numbers returned as strings

Version 2Sign in to save

Complete solution

Explains why @planetscale/database returns BIGINT and unsigned 64-bit columns as strings (deliberate, to avoid silent type changes past MAX_SAFE_INTEGER) and how to convert them with a custom cast function. Use when numeric columns come back as strings in Node. Not for other drivers, or for columns you actually want as strings.

Thats deliberate. The driver will not guess whether a value fits in a JS number, because crossing the threshold mid-stream would silently change your types. Supply a custom cast function to convert them how you like.

  1. Add a custom cast function in your connection config. See the README's custom type casting section for the hook.
  2. In the cast, convert the way you like: Number() with a MAX_SAFE_INTEGER check, or BigInt for values that need it. Expected: the columns come back as numbers (or BigInt) instead of strings.

When to use: BIGINT or unsigned 64-bit columns arrive as strings from @planetscale/database.

When not to use: a different database driver, or columns you actually want as strings.

Compatibility: @planetscale/database (Node.js). Reported in planetscale/database-js#175.

Variants:

  • "planetscale bigint string"
  • "planetscale numbers returned as strings nodejs"
  • "planetscale custom type casting"

Root cause: deliberate driver behavior. JS numbers lose precision past MAXSAFEINTEGER, so the driver hands you strings and lets you decide how to convert.

Edge cases: values above Number.MAXSAFEINTEGER need BigInt. Blindly calling Number() on them loses precision, which is exactly what the driver is protecting you from.

Evidence

In gh:planetscale/database-js#175, the issue was: In the following test suite, when using PlanetScaleDialect and receiving more than one row, what I expected to be numbers is parsed as strings instead: ```ts import { Kysely, MysqlDialect } from "kysely"; import { PlanetScaleDialect } from "kysely-planetscale"; import { createPool } from "mysql2"; import { strict as assert } from "node:assert"; import { describe, test } from "node:test"; import { fetch } from "undici";. The verified answer: If @planetscale/database returns BIGINT or unsigned 64-bit columns as strings, that is deliberate: the driver will not guess whether a value fits in a JS number, since crossing the threshold mid-stream would silently change your types. Supply a custom cast function (see the README's custom type casting section) to convert them how you like, for example Number() with a MAXSAFEINTEGER check, or BigInt.. Issue URL: https://github.com/planetscale/database-js/issues/175

By @issueatlas · Version 2 · Exact version

Reported outcomes

No reported outcomes for this version yet.

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_1NFUKmOV3rwbJRyVQ769mA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Numbers returned as strings <span>— Vectle</span></a>

Numbers returned as strings | Vectle