diff --git a/.changeset/discourage-section-blocks.md b/.changeset/discourage-section-blocks.md
new file mode 100644
index 000000000..966c5e4a3
--- /dev/null
+++ b/.changeset/discourage-section-blocks.md
@@ -0,0 +1,5 @@
+---
+'@shopify/theme-check-common': minor
+---
+
+Add `DiscourageSectionBlocks` check that warns when section-defined blocks (blocks with `settings`) are used inside a section schema, suggesting the use of theme blocks instead.
diff --git a/packages/theme-check-common/src/checks/discourage-section-blocks/index.spec.ts b/packages/theme-check-common/src/checks/discourage-section-blocks/index.spec.ts
new file mode 100644
index 000000000..d6b5cbb3b
--- /dev/null
+++ b/packages/theme-check-common/src/checks/discourage-section-blocks/index.spec.ts
@@ -0,0 +1,143 @@
+import { expect, describe, it } from 'vitest';
+import { runLiquidCheck } from '../../test';
+import { DiscourageSectionBlocks } from './index';
+
+const sectionFile = 'sections/my-section.liquid';
+
+describe('Module: DiscourageSectionBlocks', () => {
+ it('reports a section block', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Section",
+ "blocks": [
+ {
+ "type": "text",
+ "name": "Text",
+ "settings": [
+ { "type": "text", "id": "content", "label": "Content" }
+ ]
+ }
+ ]
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(1);
+ });
+
+ it('reports each section block independently', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Section",
+ "blocks": [
+ {
+ "type": "text",
+ "name": "Text",
+ "settings": []
+ },
+ {
+ "type": "image",
+ "name": "Image",
+ "settings": []
+ }
+ ]
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(2);
+ });
+
+ it('does not report theme blocks', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Section",
+ "blocks": [
+ { "type": "@app" }
+ ]
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(0);
+ });
+
+ it('does not report when there are no blocks', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Section",
+ "settings": []
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(0);
+ });
+
+ it('does not report when the schema tag is missing', async () => {
+ const source = `
No schema here
`;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(0);
+ });
+
+ it('reports section blocks but not theme blocks when mixed', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Section",
+ "blocks": [
+ { "type": "@app" },
+ {
+ "type": "text",
+ "name": "Text",
+ "settings": []
+ }
+ ]
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(DiscourageSectionBlocks, source, sectionFile);
+
+ expect(offenses).toHaveLength(1);
+ });
+
+ it('does not report for non-section files', async () => {
+ const source = `
+ {% schema %}
+ {
+ "name": "My Block",
+ "settings": [
+ {
+ "type": "text",
+ "id": "content",
+ "label": "Content"
+ }
+ ]
+ }
+ {% endschema %}
+ `;
+
+ const offenses = await runLiquidCheck(
+ DiscourageSectionBlocks,
+ source,
+ 'blocks/my-block.liquid',
+ );
+
+ expect(offenses).toHaveLength(0);
+ });
+});
diff --git a/packages/theme-check-common/src/checks/discourage-section-blocks/index.ts b/packages/theme-check-common/src/checks/discourage-section-blocks/index.ts
new file mode 100644
index 000000000..17315b7bf
--- /dev/null
+++ b/packages/theme-check-common/src/checks/discourage-section-blocks/index.ts
@@ -0,0 +1,57 @@
+import { getLocEnd, getLocStart, nodeAtPath } from '../../json';
+import { getSchema, isSection } from '../../to-schema';
+import { LiquidCheckDefinition, Severity, SourceCodeType } from '../../types';
+
+export const DiscourageSectionBlocks: LiquidCheckDefinition = {
+ meta: {
+ code: 'DiscourageSectionBlocks',
+ name: 'Discourage Section Blocks',
+ docs: {
+ description: 'Discourages the use of section blocks in favor of theme blocks.',
+ recommended: false,
+ },
+ type: SourceCodeType.LiquidHtml,
+ severity: Severity.WARNING,
+ schema: {},
+ targets: [],
+ },
+
+ create(context) {
+ if (!isSection(context.file.uri)) {
+ return {};
+ }
+
+ return {
+ async LiquidRawTag(node) {
+ if (node.name !== 'schema' || node.body.kind !== 'json') {
+ return;
+ }
+
+ const schema = await getSchema(context);
+ const { ast, validSchema } = schema ?? {};
+
+ if (!ast || ast instanceof Error || !validSchema || validSchema instanceof Error) {
+ return;
+ }
+
+ const offset = node.blockStartPosition.end;
+ validSchema.blocks?.forEach((block, index) => {
+ if (!('settings' in block)) {
+ return;
+ }
+
+ const astNode = nodeAtPath(ast, ['blocks', String(index), 'type']);
+ if (!astNode) {
+ return;
+ }
+
+ context.report({
+ message: 'Consider using a ThemeBlock instead of a SectionBlock.',
+ startIndex: offset + getLocStart(astNode),
+ endIndex: offset + getLocEnd(astNode),
+ });
+ });
+ },
+ };
+ },
+};
diff --git a/packages/theme-check-common/src/checks/index.ts b/packages/theme-check-common/src/checks/index.ts
index be0370c41..8e84d00be 100644
--- a/packages/theme-check-common/src/checks/index.ts
+++ b/packages/theme-check-common/src/checks/index.ts
@@ -10,6 +10,7 @@ import { BlockIdUsage } from './block-id-usage';
import { CdnPreconnect } from './cdn-preconnect';
import { ContentForHeaderModification } from './content-for-header-modification';
import { DeprecateBgsizes } from './deprecate-bgsizes';
+import { DiscourageSectionBlocks } from './discourage-section-blocks';
import { DeprecateLazysizes } from './deprecate-lazysizes';
import { DeprecatedFilter } from './deprecated-filter';
import { DeprecatedFontsOnSectionsAndBlocks } from './deprecated-fonts-on-sections-and-blocks';
@@ -81,6 +82,7 @@ export const allChecks: (LiquidCheckDefinition | JSONCheckDefinition)[] = [
ContentForHeaderModification,
DeprecateBgsizes,
DeprecateLazysizes,
+ DiscourageSectionBlocks,
DeprecatedFilter,
DeprecatedFontsOnSectionsAndBlocks,
DeprecatedFontsOnSettingsData,