<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andreas Bergström</title>
    <description>The latest articles on DEV Community by Andreas Bergström (@andreasbergstrom).</description>
    <link>https://dev.to/andreasbergstrom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F153469%2F5c1970f5-0d22-46e9-af0c-6931bb91d856.jpg</url>
      <title>DEV Community: Andreas Bergström</title>
      <link>https://dev.to/andreasbergstrom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andreasbergstrom"/>
    <language>en</language>
    <item>
      <title>The Last Human-First Programming Language</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Wed, 06 May 2026 19:24:49 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/the-last-human-first-programming-language-24gl</link>
      <guid>https://dev.to/andreasbergstrom/the-last-human-first-programming-language-24gl</guid>
      <description>&lt;p&gt;Programming spent forty years climbing away from the machine — garbage collection, ORMs, dynamic typing, magical frameworks — trading runtime cost for human comfort while a person was at the keyboard. If LLMs are writing most of the code, the next generation of languages won't optimise for what's pleasant to type, but for what an agent can synthesise, inspect, test, and repair without anyone stepping in.&lt;/p&gt;

&lt;p&gt;The full post argues this isn't "we all go back to C" — it's that visibility at the call site, not abstraction level, becomes the new design axis. SQL keeps its abstraction; ORMs that materialise seventeen joins from one expression don't. Walks through the AI adoption tax on new languages, why Python complicates the picture, and ends on a falsifiable bet about which TypeScript and Java backends gain share by 2029.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/the-last-human-first-programming-language" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>programming</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Cutting a MySQL table in half with one line</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 04 May 2026 19:46:45 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/cutting-a-mysql-table-in-half-with-one-line-3aom</link>
      <guid>https://dev.to/andreasbergstrom/cutting-a-mysql-table-in-half-with-one-line-3aom</guid>
      <description>&lt;p&gt;We had a wide MySQL table — 8 million rows, 8 GB on disk, mostly index — about to grow 10× from a historical backfill. The instinct was to normalise: pull repeated strings into dimension tables. Classic relational hygiene. But twenty minutes spent measuring cardinality and average length per column pointed somewhere different.&lt;/p&gt;

&lt;p&gt;The biggest single column by raw bytes was a high-cardinality, near-unique click identifier from ad platforms. Normalising it would have moved the bytes around without removing them. Meanwhile InnoDB's &lt;code&gt;ROW_FORMAT=COMPRESSED&lt;/code&gt; finds patterns &lt;em&gt;within&lt;/em&gt; strings — particularly devastating on indexed URL-shaped columns — and it ships in a one-line &lt;code&gt;ALTER TABLE&lt;/code&gt; with &lt;code&gt;ALGORITHM=INPLACE, LOCK=NONE&lt;/code&gt;, no application code changes, fully reversible.&lt;/p&gt;

&lt;p&gt;Result on the production table: 8.18 GB → 3.63 GB, with the index side compressing 59%. The full post covers the cardinality measurements, why "won't reads get slower?" usually goes the right way for analytics workloads, and when to actually reach for normalisation.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/cutting-a-mysql-table-in-half-with-one-line" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>Wiring Prisma 7 into TanStack Start on Bun</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 04 May 2026 19:46:05 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/wiring-prisma-7-into-tanstack-start-on-bun-1enp</link>
      <guid>https://dev.to/andreasbergstrom/wiring-prisma-7-into-tanstack-start-on-bun-1enp</guid>
      <description>&lt;p&gt;TanStack Start, Prisma 7, and Bun fit together cleanly, but there are a handful of small decisions you want to get right before the code lands in production. This post is the list I'd want written down before starting.&lt;/p&gt;

&lt;p&gt;Highlights: Prisma 7 moved the runtime datasource into &lt;code&gt;prisma.config.ts&lt;/code&gt; (the &lt;code&gt;url = env(...)&lt;/code&gt; form in &lt;code&gt;schema.prisma&lt;/code&gt; no longer works); &lt;code&gt;@prisma/adapter-pg&lt;/code&gt; is the shortest path on Bun and turns connection behaviour into plain &lt;code&gt;pg&lt;/code&gt; knowledge; the stash-on-&lt;code&gt;globalThis&lt;/code&gt; singleton is non-negotiable under Vite HMR; and &lt;code&gt;@map&lt;/code&gt; / &lt;code&gt;@@map&lt;/code&gt; give you snake_case in Postgres and camelCase in TypeScript with zero runtime cost.&lt;/p&gt;

&lt;p&gt;The trickiest one is keeping Prisma out of the client bundle. &lt;code&gt;createServerFn&lt;/code&gt; handles the obvious case, but a shared service module that's transitively reachable from the client graph still needs a dynamic &lt;code&gt;import('./db')&lt;/code&gt; to keep Vite from trying to bundle Node built-ins.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/wiring-prisma-7-into-tanstack-start-on-bun" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>tanstack</category>
      <category>bunjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Shipping TanStack Start and Bun to Railway</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 04 May 2026 19:45:24 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/shipping-tanstack-start-and-bun-to-railway-2o7k</link>
      <guid>https://dev.to/andreasbergstrom/shipping-tanstack-start-and-bun-to-railway-2o7k</guid>
      <description>&lt;p&gt;Railway's Nixpacks autobuild detects Bun projects fine, but it can't sequence the combination this site needs: &lt;code&gt;prisma generate&lt;/code&gt; at build time, Vite + the TanStack Start plugin, a custom &lt;code&gt;server.ts&lt;/code&gt; entry, and &lt;code&gt;prisma migrate deploy&lt;/code&gt; on boot. A four-stage Dockerfile is simpler than teaching Nixpacks all of that.&lt;/p&gt;

&lt;p&gt;The full post walks through the recipe: two parallel &lt;code&gt;bun install&lt;/code&gt; stages (one full, one production-only), a build stage that runs &lt;code&gt;prisma generate&lt;/code&gt; against a dummy &lt;code&gt;DATABASE_URL&lt;/code&gt;, a lean runtime that layers the generated Prisma client on top of &lt;code&gt;deps-prod&lt;/code&gt;'s &lt;code&gt;node_modules&lt;/code&gt;, and an entrypoint that runs migrations before &lt;code&gt;exec&lt;/code&gt;-ing into Bun so the container's PID 1 shuts down cleanly on Railway's SIGTERM.&lt;/p&gt;

&lt;p&gt;Plus the small Railway-side bits: how to wire the Postgres reference variable, why you should bind explicitly to &lt;code&gt;0.0.0.0&lt;/code&gt;, and the COPY-order detail that determines whether your runtime sees the right Prisma client.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/shipping-tanstack-start-and-bun-to-railway" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>railway</category>
      <category>docker</category>
      <category>bunjs</category>
      <category>tanstack</category>
    </item>
    <item>
      <title>Keeping the Prisma CLI out of a Bun runtime image</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 04 May 2026 19:43:22 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/keeping-the-prisma-cli-out-of-a-bun-runtime-image-1nb</link>
      <guid>https://dev.to/andreasbergstrom/keeping-the-prisma-cli-out-of-a-bun-runtime-image-1nb</guid>
      <description>&lt;p&gt;This site's runtime Docker image was 423 MB. After one Bun install flag and a one-line Dockerfile change, it's 267 MB — no functional change, just less Prisma CLI tooling sitting on disk that the server never imports.&lt;/p&gt;

&lt;p&gt;The interesting part is &lt;em&gt;why&lt;/em&gt; the obvious fix (moving &lt;code&gt;prisma&lt;/code&gt; to &lt;code&gt;devDependencies&lt;/code&gt;) doesn't do anything on its own. &lt;code&gt;@prisma/client&lt;/code&gt; declares &lt;code&gt;prisma&lt;/code&gt; as an &lt;em&gt;optional peer dependency&lt;/em&gt;, and Bun installs optional peers by default. From there, transitive deps drag in &lt;code&gt;@prisma/engines&lt;/code&gt;, &lt;code&gt;@prisma/studio-core&lt;/code&gt;, &lt;code&gt;@electric-sql/pglite&lt;/code&gt;, and ~160 MB of code the server never imports.&lt;/p&gt;

&lt;p&gt;The fix is &lt;code&gt;bun install --omit=peer&lt;/code&gt;, plus narrowing the runtime stage's &lt;code&gt;COPY --from=builder /app/node_modules/@prisma&lt;/code&gt; line to just &lt;code&gt;@prisma/client&lt;/code&gt;. The full post covers the trap, the fix, and where migrations have to run once the CLI is gone from the runtime image.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/keeping-the-prisma-cli-out-of-a-bun-runtime-image" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bunjs</category>
      <category>prisma</category>
      <category>docker</category>
      <category>railway</category>
    </item>
    <item>
      <title>The LLM-shaped hole in your XGBoost pipeline</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 04 May 2026 19:43:19 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/the-llm-shaped-hole-in-your-xgboost-pipeline-3m7f</link>
      <guid>https://dev.to/andreasbergstrom/the-llm-shaped-hole-in-your-xgboost-pipeline-3m7f</guid>
      <description>&lt;p&gt;Every team shipping a tabular ML model gets the same question from leadership eventually: &lt;em&gt;"Have we tried GPT for this?"&lt;/em&gt; The honest answer is that gradient-boosted trees still beat everything else on tabular prediction, and that hasn't changed because LLMs got bigger. TabPFN, FT-Transformer, and friends are interesting, but the short list of serious alternatives stays short.&lt;/p&gt;

&lt;p&gt;There &lt;em&gt;is&lt;/em&gt; an LLM-shaped hole in most XGBoost pipelines — it's just not where most people put it. The pattern that works is LLMs &lt;em&gt;upstream&lt;/em&gt; of trees: embeddings as features, text-to-features extraction over unstructured fields, and tool-using agents to fill enrichment gaps. None of these touch the prediction path; they all feed signal into the model that does.&lt;/p&gt;

&lt;p&gt;The full post walks through cost math, what each pattern is worth in practice, and the cases where the empirical answer turns out to be "no, the embeddings don't help."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/the-llm-shaped-hole-in-your-xgboost-pipeline" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Using FastMCP with OpenAI and Avoiding Session Termination Issues</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sun, 10 Aug 2025 10:32:13 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/using-fastmcp-with-openai-and-avoiding-session-termination-issues-k3h</link>
      <guid>https://dev.to/andreasbergstrom/using-fastmcp-with-openai-and-avoiding-session-termination-issues-k3h</guid>
      <description>&lt;p&gt;If you're plugging a FastMCP server into OpenAI's Responses API and your sessions keep dying with &lt;code&gt;Session has been terminated&lt;/code&gt;, the fix is one flag: &lt;code&gt;stateless_http=True&lt;/code&gt; when you instantiate &lt;code&gt;FastMCP(...)&lt;/code&gt;. OpenAI sends a &lt;code&gt;DELETE&lt;/code&gt; after each call without recreating the session, so anything stateful gets terminated between requests.&lt;/p&gt;

&lt;p&gt;The full post covers the JSON-RPC error you'll actually see, the minimal server change to make it work, and the caveats — session state and certain bi-directional streaming patterns drop out in stateless mode. Worth a quick read if you're hitting the same one-call-then-broken behaviour.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/fastmcp-openai-session-termination" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>fastmcp</category>
      <category>openai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Redirecting mobile users to App or Play Store in NextJS</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 27 Nov 2023 19:53:11 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/redirecting-mobile-users-to-app-or-play-store-using-nextjs-3pp1</link>
      <guid>https://dev.to/andreasbergstrom/redirecting-mobile-users-to-app-or-play-store-using-nextjs-3pp1</guid>
      <description>&lt;p&gt;If you're promoting a mobile app for both iOS and Android and want a single URL or QR code that drops users into the correct store, you don't need a 3rd-party redirect service. A NextJS middleware that matches &lt;code&gt;userAgent&lt;/code&gt; against &lt;code&gt;iP(hone|ad|od)&lt;/code&gt; and &lt;code&gt;Android&lt;/code&gt; regexes does it in ~15 lines, runs before any render, and keeps the contact point — and any SEO it earns — on your own domain.&lt;/p&gt;

&lt;p&gt;The full post walks through the &lt;code&gt;middleware.ts&lt;/code&gt; plus the placeholder &lt;code&gt;app/get.tsx&lt;/code&gt; page that triggers it, with notes on the iOS-vs-Android UX quirk and why owning that redirect matters once QR codes are out in the wild and outlive your vendor relationships.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/nextjs-mobile-app-store-redirect" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>mobile</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Python del vs assigning to None</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sat, 11 Nov 2023 16:37:38 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/python-del-vs-assigning-to-none-5387</link>
      <guid>https://dev.to/andreasbergstrom/python-del-vs-assigning-to-none-5387</guid>
      <description>&lt;p&gt;Both &lt;code&gt;x = None&lt;/code&gt; and &lt;code&gt;del x&lt;/code&gt; look like ways to release a variable in Python, but they aren't equivalent. &lt;code&gt;x = None&lt;/code&gt; keeps the name bound and just rebinds it to &lt;code&gt;NoneType&lt;/code&gt; (still ~16 bytes); &lt;code&gt;del x&lt;/code&gt; removes the binding entirely so the name itself is gone. Touch &lt;code&gt;x&lt;/code&gt; after &lt;code&gt;del&lt;/code&gt; and you get a &lt;code&gt;NameError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The full post walks through a worked example with &lt;code&gt;sys.getsizeof&lt;/code&gt; and &lt;code&gt;gc.collect()&lt;/code&gt; showing the byte difference, then disassembles both versions with &lt;code&gt;dis.dis&lt;/code&gt; so you can see &lt;code&gt;del&lt;/code&gt; compiles to a single &lt;code&gt;DELETE_FAST&lt;/code&gt; while assigning to &lt;code&gt;None&lt;/code&gt; becomes a &lt;code&gt;LOAD_CONST&lt;/code&gt; + &lt;code&gt;STORE_FAST&lt;/code&gt; pair.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/python-del-vs-none" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>performance</category>
    </item>
    <item>
      <title>Node 21 brings built-in WebSocket support</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Mon, 16 Oct 2023 18:19:32 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/node-21-might-have-websockets-built-in-24f3</link>
      <guid>https://dev.to/andreasbergstrom/node-21-might-have-websockets-built-in-24f3</guid>
      <description>&lt;p&gt;Node 21 finally ships with a built-in WebSocket client — no more pulling in &lt;code&gt;ws&lt;/code&gt; or &lt;code&gt;socket.io-client&lt;/code&gt; for a basic browser-style API on the server side. Deno and Bun have shipped this for a while; this closes the gap.&lt;/p&gt;

&lt;p&gt;The full post (written just ahead of the v21 release) tracks the upstream Undici PR and the long-running Node issue thread that pushed it across the finish line, with a link to the v21 release announcement once it landed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/node-21-built-in-websocket" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>Configure TypeORM migrations in 5 minutes</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sun, 15 Oct 2023 08:39:24 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/configure-typeorm-migrations-in-5-minutes-2njg</link>
      <guid>https://dev.to/andreasbergstrom/configure-typeorm-migrations-in-5-minutes-2njg</guid>
      <description>&lt;p&gt;Setting up TypeORM migrations in a NestJS project is fiddly across two configs and four npm scripts the first time you do it, but mechanical once you know the shape. Wire &lt;code&gt;migrationsRun: true&lt;/code&gt; into &lt;code&gt;TypeOrmModule.forRootAsync&lt;/code&gt;, add a separate &lt;code&gt;typeorm.config.ts&lt;/code&gt; &lt;code&gt;DataSource&lt;/code&gt; for the CLI to import, and four package.json scripts cover run/generate/create/revert.&lt;/p&gt;

&lt;p&gt;The full post has the exact &lt;code&gt;app.module.ts&lt;/code&gt;, &lt;code&gt;typeorm.config.ts&lt;/code&gt;, and &lt;code&gt;package.json&lt;/code&gt; snippets to copy, plus notes on why &lt;code&gt;synchronize&lt;/code&gt; should never be true in production and how &lt;code&gt;generate-migration&lt;/code&gt; diffs your entities against the live schema to write the SQL for you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/typeorm-migrations-nestjs" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>typeorm</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Easily style active links in Tanstack Router</title>
      <dc:creator>Andreas Bergström</dc:creator>
      <pubDate>Sat, 14 Oct 2023 07:45:23 +0000</pubDate>
      <link>https://dev.to/andreasbergstrom/easily-style-active-links-in-tanstack-router-7n</link>
      <guid>https://dev.to/andreasbergstrom/easily-style-active-links-in-tanstack-router-7n</guid>
      <description>&lt;p&gt;TanStack Router's &lt;code&gt;Link&lt;/code&gt; accepts an &lt;code&gt;activeProps&lt;/code&gt; prop that gets spread onto the rendered element only when the link matches the current route — including &lt;code&gt;className&lt;/code&gt;. So styling the active item in a navbar is just &lt;code&gt;&amp;lt;Link activeProps={{ className: 'text-black' }}&amp;gt;&lt;/code&gt; — no &lt;code&gt;useMatches&lt;/code&gt;, no manual &lt;code&gt;pathname&lt;/code&gt; comparison.&lt;/p&gt;

&lt;p&gt;The full post has a short &lt;code&gt;MainNav&lt;/code&gt; example mapping menu items to &lt;code&gt;Link&lt;/code&gt;s plus a pointer to TanStack's docs for the rest of the active-state knobs.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://andreasbergstrom.dev/posts/tanstack-router-active-link-styles" rel="noopener noreferrer"&gt;andreasbergstrom.dev&lt;/a&gt; — read the full post there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
  </channel>
</rss>
