Skip to content

Question marks in frontmatter converted to PostgreSQL placeholders ($1, $2, etc.) #3682

@giticon

Description

@giticon

Environment

Bug: Question marks in frontmatter converted to PostgreSQL placeholders ($1, $2, etc.)

Environment

  • Nuxt Content Version: 3.10.0
  • Nuxt Version: 4.2.2
  • Database: PostgreSQL (Neon) - Vercel
  • Node Version: 24.x
  • pg Package Version: 8.16.3

Description

When using PostgreSQL as the database backend for Nuxt Content v3, question marks (?) in frontmatter fields are incorrectly converted to PostgreSQL parameter placeholders ($1, $2, $3, etc.) when the content is indexed.

Version

v3.10.0

Reproduction

Steps to Reproduce

  1. Configure Nuxt Content to use PostgreSQL:
// nuxt.config.ts
export default defineNuxtConfig({
  content: {
    database: {
      type: 'postgresql',
      url: process.env.POSTGRES_URL
    }
  }
})
  1. Create a markdown file with a question mark in the frontmatter:
---
faqid: 1
category: "general"
question: "How much does it cost?"
---

Answer content here.
  1. Configure the collection:
// content.config.ts
export default defineContentConfig({
  collections: {
    faq: defineCollection({
      type: "data",
      source: "faq/**.md",
      schema: z.object({
        faqid: z.number(),
        category: z.string(),
        question: z.string(),
      }),
    }),
  },
})
  1. Query the collection:
const { data } = await useAsyncData('faq', () =>
  queryCollection('faq').all()
)
  1. Display the frontmatter field:
<span>{{ item.question }}</span>

Description

Expected Behavior

The question mark should be preserved and displayed as: "How much does it cost?"

Actual Behavior

The question mark is converted to a PostgreSQL placeholder and displayed as: "How much does it cost$1"

Multiple question marks in the same field result in sequential placeholders: $1, $2, $3, etc.

Additional Observations

  • Works correctly with SQLite: The issue does NOT occur when using the default SQLite database in development
  • Only affects PostgreSQL: The bug only manifests when using PostgreSQL as the production database
  • Escaping doesn't work: Attempting to escape with \? results in displaying \$1 instead of ?
  • Quotes don't help: Adding quotes around the frontmatter value (single or double) doesn't prevent the issue
  • Affects all question marks: Every ? character in the string is converted to a sequential placeholder

Workaround

Currently using a client-side fix to replace placeholders back to question marks:

const fixPlaceholders = (text) => {
  if (!text) return text;
  // Fix PostgreSQL placeholder bug: replace $1, $2, etc. with ?
  return text.replace(/\$\d+/g, '?');
};
<span>{{ fixPlaceholders(item.question) }}</span>

Possible Cause

The issue likely stems from PostgreSQL's prepared statement placeholder syntax ($1, $2, etc.) being incorrectly applied to the content itself rather than just query parameters during the indexing/storage phase.

It appears that when Nuxt Content processes markdown files and stores them in PostgreSQL, the question mark character is being treated as a special character in the SQL context and replaced with parameter placeholders.

Impact

This bug makes it impossible to use question marks in any frontmatter field when using PostgreSQL as the backend, which is particularly problematic for:

  • FAQ systems (questions naturally end with ?)
  • Any content that includes interrogative sentences
  • Multi-language content where question marks are common

Additional context

Related Information

  • PostgreSQL uses $1, $2, etc. for parameterized queries
  • The pg package is being used (version 8.16.3)
  • This appears to be a server-side issue during content indexing, not a client-side rendering issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions