· ·

Content SDK 1.1: Three Changes Worth Your Attention

Alex Lentz

Title card: Content SDK 1.1: Three Changes Worth Your Attention. Content SDK post on Sitecore Saga.

Content SDK 1.1 shipped last week (September 23rd), and since 1.0 only went stable in July, this is the first “real” upgrade a lot of XM Cloud teams are going to do on the new SDK.

The release notes cover a lot – Design Library enablers, display name routing fixes, cache busting changes – but there are three things I’d actually look at before bumping the version on a client project. One of them can quietly break your editing host if you’re not on a standard setup.

1. Editing render no longer redirects – it calls itself

This is the one to read twice.

In 1.0, when Pages asked your editing host to render a page, the editing render middleware handed back a temporary redirect to the page route. In 1.1 that’s gone. The middleware now makes an internal server request to your own Next.js app to fetch the page data. Fewer round trips, faster editing, all good – as long as the app can actually reach itself.

How it figures out where “itself” is:

  1. sitecoreInternalEditingHostUrl in sitecore.config.ts, if you set it
  2. The SITECORE_INTERNAL_EDITING_HOST_URL environment variable
  3. If neither is set: http://localhost:3000 when running in XM Cloud, or the incoming request’s host header on Vercel / Netlify

For the default XM Cloud editing host and a vanilla Vercel deployment, you don’t need to do anything. Where I’d expect trouble:

  • Your editing host runs on a port other than 3000
  • It’s behind a reverse proxy or App Gateway where the public host name doesn’t resolve from inside the container
  • You’ve got a custom base path

If your editing host starts throwing errors in Pages after the upgrade, this is the first place to look. Set it explicitly:

// sitecore.config.ts
import { defineConfig } from '@sitecore-content-sdk/nextjs/config';

export default defineConfig({
  // Where the editing host can reach itself from the server side
  sitecoreInternalEditingHostUrl: process.env.SITECORE_INTERNAL_EDITING_HOST_URL,
});
# .env (editing host only)
SITECORE_INTERNAL_EDITING_HOST_URL=http://localhost:8080

I like keeping it env-driven even though the config property would win on its own. That way the same code works on the XM Cloud editing host, a Docker container and a dev box without a code change.

2. ESLint 9 and the flat config

The SDK and the starter moved from ESLint 8 to ESLint 9, which means .eslintrc is out and eslint.config.mjs is in. If you scaffolded from the 1.0 starter, your lint setup is going to fail the first time you npm install the new versions.

The new template config is pretty readable. The shape looks like this:

// eslint.config.mjs (trimmed)
import { defineConfig } from 'eslint/config';
import js from '@eslint/js';
import * as nextEslintPlugin from '@next/eslint-plugin-next';
import tsParser from '@typescript-eslint/parser';

const nextPlugin = nextEslintPlugin.default ?? nextEslintPlugin;

export default defineConfig([
  { ignores: ['node_modules/**', '.next/**', 'dist/**'] },
  js.configs.recommended,
  { plugins: { '@next/next': nextPlugin } },
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    languageOptions: { parser: tsParser },
    rules: {
      ...(nextPlugin.configs?.recommended?.rules ?? {}),
      '@next/next/no-img-element': 'off',
    },
  },
]);

My advice: don’t hand-convert your old .eslintrc. Copy the template’s eslint.config.mjs from a fresh npx create-content-sdk-app, then port over only the custom rules you actually care about. Most of us have rules in there that nobody remembers adding.

3. Cursor rules in the starter

This is the fun one. The Next.js starter now ships with a .cursor/rules folder:

.cursor/rules/
  general.mdc
  javascript.mdc
  project-setup.mdc
  sitecore.mdc

Each .mdc file has frontmatter that tells Cursor when to pull it in – sitecore.mdc for example is scoped with globs to src/components/**, src/lib/** and sitecore.config.ts. So when you ask Cursor to build a component, it already knows to use the Sitecore field components, to handle empty fields, to follow the naming conventions and so on.

I’ve been leaning on AI-assisted development a lot this year, and the biggest quality jump always comes from giving the model your team’s conventions, not the framework’s. The shipped rules are a solid base. Add your own on top:

---
description: Team conventions for Sitecore components
alwaysApply: false
globs:
  - 'src/components/**'
---

# Team component conventions

- Every rendering gets a matching `*.stories.tsx` file with an empty-fields story
- Datasource fields are typed with the Content SDK field types, never `any`
- Never hard-code copy. If an author might want to change it, it's a field or a dictionary entry
- Images always go through the Sitecore `Image` component so editing keeps working
- Keep components presentational. Data fetching lives in `getComponentServerProps`

Drop that in .cursor/rules/team-components.mdc and commit it. Now every developer on the team (and every AI assistant they use) works from the same playbook.

Should you upgrade?

Yes, but read the 1.1 upgrade guide first and test editing specifically – not just the public site. Here’s the checklist I’m using:

  • Bump the @sitecore-content-sdk/* packages together
  • Replace .eslintrc with the new flat config
  • Verify editing in Pages on a non-prod environment
  • If editing breaks, set SITECORE_INTERNAL_EDITING_HOST_URL
  • Grab the .cursor/rules folder from a fresh starter, even if you’re not using Cursor today – they double as decent onboarding docs

Resources

Alex Lentz

Alex Lentz

Senior Solutions Architect at Americaneagle.com and two-time Sitecore Technology MVP. Building on Sitecore since 2013, mostly SitecoreAI and headless Next.js these days.

LinkedIn    GitHub

Keep reading