camelCase vs snake_case: Naming Conventions in Laravel, WordPress and JavaScript

camelCase vs snake_case: Naming Conventions in Laravel, WordPress and JavaScript

In a single working day I can easily write code in three naming styles. Laravel models are PascalCase, database columns are snake_case, the JavaScript on the same page is camelCase, and the URLs are kebab-case. Switch to a WordPress plugin and the rules change again.

None of this is random. Each style belongs to a convention, and following the convention is what makes frameworks like Laravel “just work”. This is the reference I wish I'd had when I started, with the conventions I follow on Laravel and WordPress projects.

The naming styles in one table

StyleExampleTypical use
camelCaseledgerEntryJavaScript variables and functions, PHP methods
PascalCase (StudlyCase)LedgerEntryPHP and JavaScript classes, Laravel models, React components
snake_caseledger_entryDatabase tables and columns, WordPress functions
kebab-caseledger-entryURLs, CSS classes, file names
CONSTANT_CASELEDGER_ENTRYConstants and environment variables

Laravel's documentation calls PascalCase “StudlyCase”, which is where its Str::studly() helper gets its name.

Laravel's conventions

Laravel relies on naming conventions so you don't have to configure everything by hand. Imagine an accounting app with invoices, customers, suppliers and ledger entries:

ThingConventionExample
ModelSingular, PascalCaseLedgerEntry
TablePlural, snake_caseledger_entries
Columnssnake_caseopening_balance, created_at
Foreign keySingular model name + _idcustomer_id
Pivot tableBoth singular model names, alphabetical, snake_caseproduct_supplier
ControllerSingular, PascalCase + ControllerLedgerEntryController
Methods and relationshipscamelCaseledgerEntries()
Route URIPlural, kebab-case/ledger-entries
Config keyssnake_caseconfig('app.timezone')
Environment variablesCONSTANT_CASEDB_DATABASE

Follow these and Eloquent works out the table name, foreign keys and pivot tables on its own. Break them and you'll be passing table and key names into every relationship by hand.

One detail that surprises people

Relationship methods are camelCase, but when a model is turned into JSON or an array, Laravel converts loaded relationships to snake_case keys. A ledgerEntries() relationship appears as "ledger_entries" in the JSON. This behaviour comes from the $snakeAttributes property on Eloquent models, which is true by default.

Accessors follow the same pattern. In Laravel 9 and later you define an accessor as a camelCase method, such as protected function fullName(): Attribute, but you read it as $customer->full_name. If you want it in JSON, add 'full_name' to the model's $appends array.

WordPress and WooCommerce conventions

The WordPress PHP coding standards are older than PSR and look different from Laravel:

  • Functions and variables: lowercase snake_case, with a unique prefix to avoid clashes with other plugins, for example kbl_get_order_total().
  • Classes: capitalised words separated by underscores, such as WC_Product or WP_Query.
  • Hooks: snake_case, such as woocommerce_before_cart.
  • Files: lowercase with hyphens. Class files are usually named after the class with a class- prefix, for example class-wc-product.php.
  • Constants: CONSTANT_CASE, such as WP_DEBUG.

When I move between a Laravel codebase and a WooCommerce plugin, the hardest part isn't the logic; it's remembering which conventions belong to which project. Mixing them in one codebase is what makes code look messy to the next developer.

JavaScript and CSS conventions

  • Variables and functions: camelCase, such as orderTotal or calculateTax().
  • Classes and React or Vue components: PascalCase, such as InvoiceTable.
  • Constants: CONSTANT_CASE for true constants, such as MAX_UPLOAD_MB.
  • CSS classes: kebab-case, such as .invoice-table, which also matches what Bootstrap and most CSS frameworks use.

Where the styles collide: JSON between Laravel and JavaScript

The real friction is at the boundary. Laravel sends JSON with snake_case keys straight from the database columns, while JavaScript code naturally wants camelCase. You'll see the same split in third-party APIs. Stripe's REST API returns snake_case fields such as client_secret and amount_received, while Stripe.js on the front end takes options in camelCase, such as clientSecret.

There are three sensible ways to deal with it:

  1. Keep snake_case end to end. Use the API's keys as they are in your JavaScript: invoice.created_at. It looks slightly odd in JavaScript, but there's nothing to convert and nothing to get out of sync. For small projects it's often the most practical option.
  2. Convert in an API Resource. Laravel's API Resources let you choose the exact keys you send, for example 'createdAt' => $this->created_at. It's explicit, and it also stops you accidentally exposing columns you didn't mean to.
  3. Convert once on the front end. A small helper that converts keys when the response arrives keeps your JavaScript consistently camelCase. The important part is doing it in one place, not ad hoc in every component.
The rule that matters most: choose one approach per project and write it down. Most naming bugs I've seen come from a mix of approaches, where half the code expects customerId and the other half sends customer_id.

When an API response doesn't match what you expect, paste it into the JSON Formatter. Seeing the structure laid out with proper indentation makes a misnamed key obvious in seconds.

A trap on Windows: table name case in MySQL

Many developers in Pakistan, me included, learned on XAMPP or WAMP on Windows. Here's a trap that catches people when they first deploy to a Linux server. MySQL's lower_case_table_names setting defaults to 1 on Windows, where table names are treated case-insensitively, but to 0 on Linux, where they're case-sensitive. A query for Invoices that worked on your laptop can fail in production because the table is actually named invoices.

The simple fix is to follow the convention: always name tables and columns in lowercase snake_case, and the problem never appears.

Converting between styles quickly

Inside a Laravel app, the Str helper handles conversions:

HelperInputOutput
Str::camel()ledger_entryledgerEntry
Str::studly()ledger_entryLedgerEntry
Str::snake()LedgerEntryledger_entry
Str::kebab()LedgerEntryledger-entry

Outside your code, when you're renaming a list of fields from a client's spreadsheet into column names or turning headings into URL slugs, paste the list into the Case Converter. Each line is converted separately, so “Opening Balance” and “Customer ID” become opening_balance and customer_id in one click. It supports camelCase, PascalCase, snake_case, kebab-case and CONSTANT_CASE, and everything runs in your browser.

Written by Aqif Akhtar

Aqif is a full-stack PHP & WordPress developer in Lahore and a Junior Software Engineer at Fidigy, where he builds Laravel applications and WooCommerce and Shopify stores. He built the tools on Wartatren.biz.id. More about Aqif.