Skip to content
ブログに戻る
チュートリアル

camelCase vs snake_case vs kebab-case — 2026 年版 命名規則ガイド

camelCase vs snake_case vs kebab-case 2026 ガイド — 6 つの case + 7 言語の意思決定マトリクス + 頭字語ルール + URL スラッグ SEO + 6 つの変換落とし穴。

14 分で読める

camelCase vs snake_case vs kebab-case — 2026 年版 命名規則ガイド

userIDuserId か。user_profileuserProfile か。URL は -_ か。こうした疑問が毎日のように PR レビューを脱線させる。これは個人の好みの問題ではない。主流の言語と Web 標準にはそれぞれ確立されたルールがあり、一覧で並べれば議論の余地は消える。

本ガイドでは、コードで実際に出会う 6 つの case(camelCase、PascalCase、snake_case、kebab-case、CONSTANT_CASE、dot.case / path/case / Header-Case)、7 言語の意思決定マトリクス、GitHub データを踏まえた parseUrl 対 parseURL の頭字語論争、kebab-case URL の SEO 上の根拠、そして case 間を自動変換するときに足元をすくう 6 つの落とし穴を扱う。任意の文字列に対して 15 種類すべての case 出力をまとめて確認するなら、ケース変換ツールがブラウザ上で即座に結果を返す。

6 つの case を一目で

比較に入る前に、まずチートシートを示す。印刷でもチーム wiki への貼り付けでも、タブで開いておくのでもよい。

Case スタイル典型的な用途起源 / 普及の立役者
camelCaseuserProfileImageJS、TS、Java、Swift の変数とメソッドSmalltalk → Java
PascalCaseUserProfileImageクラス、React/Vue コンポーネント、TS の型Pascal 言語
snake_caseuser_profile_imagePython、Ruby、Rust、SQL のカラムC / 初期の Unix
kebab-caseuser-profile-imageCSS クラス、URL スラッグ、HTML 属性Lisp / モダン Web
CONSTANT_CASEUSER_PROFILE_IMAGE環境変数、トップレベル定数、マクロC のマクロ / Unix 環境変数
dot.caseuser.profile.imageJava パッケージ、MongoDB パス、TOML キー名前空間の慣習
path/caseuser/profile/imageURL パス、ファイルシステム、Git の refUnix のパス
Header-CaseUser-Profile-ImageHTTP/1.1 ヘッダー名(canonical)RFC 2616

「本物の」case は 6 つだが表は 8 行ある。dot.case、path/case、Header-Case は同じトークン化を区切り文字違いで共有しているからだ。多くの case ライブラリはこれらを一つのファミリーとして扱う。

各 case の深掘り

camelCase: JS/Java のデフォルト

camelCase のアイデア自体は Smalltalk のものだが、業界に広めた言語は Java だ。Sun が 1995 年に発表した Java コーディング規約が firstNamegetUserProfilexmlParser を標準の綴りに据え、Java 風に見せたかった言語、つまり JavaScript、ActionScript、Swift、Kotlin、Dart はみな同じ形を受け継いだ。

ルールはこうだ。最初の単語を全部小文字にし、それ以降の単語の先頭だけ大文字にし、区切り文字は消す。アンダースコアなし、ハイフンなし、スペースなし。「camelCase」という名前は、小文字の海から大文字が突き出す凸凹の輪郭に由来する。

境界事例は 2 つある。1 つは小文字で始まるブランド名(iPhoneeBayiOS)。これらがコード中に現れたとき、i を大文字にしてはいけない。ブランドの綴りどおりに書き、少し変に見える識別子のまま受け入れる。もう 1 つは頭字語で、こちらは後ろの節で扱う。

PascalCase: クラスとコンポーネント

PascalCase は最初の 1 文字を大文字にした camelCase でしかない。一部のスタイルガイドはこれを「UpperCamelCase」と呼ぶ。Pascal 言語が 1970 年代にこの書き方を用い、名前がそのまま定着した。

主な居場所はこうだ。C 系オブジェクト指向言語(Java、C#、C++、Kotlin、Swift、TypeScript)のクラス名、React/Vue/Angular のコンポーネント名、TypeScript の型エイリアスとインターフェース(type UserProfileinterface AuthState)、そして一部のエコシステムにおけるモジュール / ファイル名(C# の UserService.cs など)。

なぜクラス用に別の case を用意するのか。視覚的なシグナルとして役立つからだ。new userProfile()new UserProfile() を読み比べれば、後者は即座に型に見え、前者は壊れた関数呼び出しに見える。値と型の名前空間を混在させる言語は、曖昧さの解消を大文字小文字の差に頼っている。

snake_case: Python、Ruby、Rust、SQL

snake_case は多くの人が思うより古い。C と初期の Unix は errno_hfopen_s のような名前を使っていた。PDP-11 のターミナルではアンダースコアが打ちやすく、Pascal 風の大文字小文字は面倒だったからだ。Python はこれを PEP 8 の公式規約として採用し、Ruby のコミュニティも自然と落ち着き、Rust は変数が userId だと文句を言う lint まで備えてコンパイラ強制のデフォルトとした。

ルールはこうだ。すべて小文字にし、単語をアンダースコアでつなぐ。user_profile_imageparse_htmlmax_retries

データベースの観点は見落とされがちだが重要だ。SQLAlchemy、Hibernate、Sequelize、TypeORM、Active Record と、ほぼすべての SQL ORM はホスト言語の慣習に関係なく、デフォルトのカラム名を snake_case にする。理由は移植性だ。PostgreSQL は引用符なしの識別子を小文字に畳み込む。MySQL は Linux では大文字小文字を区別し、macOS / Windows では区別しない。SQLite はカラム名を不透明な文字列として扱う。snake_case はこれらすべてを引用符なしで生き残れる綴りだ。

kebab-case: Web の選択

Web はユーザーから見える要素のほとんどで kebab-case に収束した。CSS クラス名(.user-profile-image)、URL スラッグ(/blog/naming-conventions-guide)、HTML のカスタム属性(data-user-id)、Web Components のタグ名(<user-card> — 仕様でハイフンを含むことが要求される)。

名前そのものについては、古いドキュメントを漁れば 8 種類ほどの異名が出てくる。「dash-case」「spinal-case」「lisp-case」「skewer-case」「hyphen-case」。どれも同じものを指す。「kebab-case」が定着したのは、単語が串に刺さった肉に見えるという Stack Overflow の古いジョークがきっかけだ。

見落としやすいルールが 1 つある。HTML と CSS のクラス名は実用上は大文字小文字を区別しないが、canonical な綴りは小文字だ。.User-Profile はほとんどのブラウザで動くが、クラス名をハッシュ化するサーバーサイドツールを壊し、コードレビュアーを混乱させる。小文字を貫くこと。

CONSTANT_CASE: 環境変数とマクロ

CONSTANT_CASE(Rust 界隈では SCREAMING_SNAKE_CASE とも呼ぶ)は、「この値は実行時には変わらない」を意味するシグナルとしてどの言語にも通じる。MAX_RETRIESAPI_KEYDEFAULT_TIMEOUT_MS。どの CI システム、コンテナランタイム、シェルも、環境変数はこの case で書かれていることを期待する(DATABASE_URLNODE_ENVPATH)。

罠を 1 つ。JavaScript の const キーワードは「CONSTANT_CASE を使え」という意味ではない。const result = await fetch(url) は正しい camelCase だ。CONSTANT_CASE は意味論的に真の定数、つまり C で #define で書いていたような値、実行時に値を変えたらバグになる類のものに取っておく。MAX_RETRIES = 3 はそれに当てはまる。result は当てはまらない。

dot.case、path/case、Header-Case

同じトークナイザーを区切り文字違いで共有する 3 兄弟だ。

dot.case は階層キーを表す。Java のパッケージ(com.example.service)、MongoDB のフィールドパス(user.profile.image)、TOML / INI の設定キー([database.primary])、Lodash のメソッドパス(_.get(obj, 'user.profile.image'))。dot.case の文字列は「名前空間、名前空間、葉」と読むのが正しい。

path/case はリテラルな場所を表す。URL パス、ファイルシステムのパス、Git の ref(feature/add-auth)。ドットとスラッシュの選択は意味を持つ。スラッシュは「これはどこかにある実体だ」、ドットは「これはラベルだ」というシグナルになる。

Header-Case は HTTP/1.1 の慣習だ。Content-TypeAccess-Control-Allow-OriginX-Forwarded-For。HTTP/1.1 のヘッダーは技術的には大文字小文字を区別しない(RFC 2616)ので content-type でも動く。だが、どのフレームワーク、どのドキュメント、どの開発者も Header-Case の綴りを期待する。HTTP/2 と HTTP/3 はこの状況を変えた。RFC 7540 §8.1.2 は、ヘッダー圧縮(HPACK)の簡素化のため、ワイヤ上のヘッダー名を小文字にすることを義務付けている。アプリケーションコードからはこの変化は見えない。HTTP/2 のクライアントとサーバーが正規化してくれるからだ。ただし、生の HTTP/2 フレームを覗き込めば、ヘッダーはすべて小文字の kebab-case になっている。

7 言語の意思決定マトリクス

命名論争を最速で片付けるには、その言語の標準ライブラリの慣習を見ればよい。マトリクスを示す。

言語変数関数クラス定数ファイル名DB カラム
Python (PEP 8)snake_casesnake_casePascalCaseCONSTANT_CASEsnake_case.pysnake_case
JavaScript/TScamelCasecamelCasePascalCaseCONSTANT_CASEkebab-case.jssnake_case
GocamelCase*PascalCase**PascalCasemixedCase***snake_case.gosnake_case
Rustsnake_casesnake_casePascalCaseSCREAMING_SNAKEsnake_case.rssnake_case
JavacamelCasecamelCasePascalCaseCONSTANT_CASEPascalCase.javasnake_case
C#camelCase†PascalCasePascalCasePascalCasePascalCase.cssnake_case
SQLn/asnake_casen/an/an/asnake_case
  • * Go: 先頭が小文字なら unexported(パッケージプライベート)、先頭が大文字なら exported(公開)を意味する。コンパイラがこれを強制する。
  • ** Go: 公開関数は PascalCase(http.NewRequest)、パッケージプライベートな関数は camelCase(http.parseHeader)。
  • *** Go: 定数も同じ大文字小文字ルールに従う。公開なら MaxRetries、非公開なら maxRetries。Go は意図的に CONSTANT_CASE を避けている。
  • C#: ローカル変数と private フィールドは camelCase(フィールドに _ を前置するコードベースもある: _userName)、public プロパティ、メソッド、型は PascalCase。

どの言語にも横断するレイヤーが 3 つある。

HTML と CSS:クラス名と ID は kebab-case(<div class="user-profile-card">)。HTML のカスタム属性は data- を前置した kebab-case(data-user-id)。インライン CSS プロパティは kebab-case(background-color)。JS の DOM 等価物は camelCase(element.style.backgroundColor)。

HTTP:送信ヘッダー名は HTTP/1.1 では Header-Case('Content-Type': 'application/json')、HTTP/2 のワイヤでは小文字の kebab-case。ほとんどの fetch ライブラリはどちらの綴りも受け付け、内部で正規化する。

環境変数:どこでも CONSTANT_CASE — Node、Python、Go、Rust、Bash、Docker、Kubernetes。.env ファイルの慣習も同じだ:DATABASE_URL=postgres://...

頭字語の扱い: Google vs Microsoft

コードレビューで最も論争を呼ぶ命名の問題だ。parseUrlparseURL か。userIduserID か。HtmlParserHTMLParser か。XmlHttpRequestXMLHttpRequest か。

流派は 2 つあり、どちらにも現実世界の権威が後ろ盾している。

頭字語を単語として扱う(Google、Apple、モダン JS)parseUrluserIdHtmlParser。Google JavaScript Style Guide §5.3 がこれを明示的に推奨する。Apple の Swift API Design Guidelines も同様だ。lodash と change-case パッケージはデフォルトでこの出力を生成する。論拠はラウンドトリップの安定性にある。parseUrlparse / url にトークン化され、parse_url に変換され、情報損失なく parseUrl に戻る。一方、parseURLparse / URL にトークン化され、素朴なトークナイザーなら parse_u_r_l、頭字語対応のトークナイザーなら parse_url になる。しかしその parse_url から戻るとき、parseUrlparseURL のどちらに戻すべきかは決まらない。全部小文字の綴りが頭字語のシグナルを失っているためだ。

頭字語の大文字を保持する(Microsoft、.NET、古めの Java)parseURLuserIDHTMLParserXMLHttpRequest。Microsoft の .NET Naming Guidelines はこれを 2-3 文字の頭字語(IOURLXML)に限定し、それより長いものは単語として扱う(厳密に読めば Html は大文字保持になるはずだが、Microsoft 自身は HtmlAgilityPack と書いている)。Win32 API、.NET BCL、そして 2010 年以前の Java コードの多くはこの流派だ。英語話者にはこちらのほうが自然に読める。parseURL は「parse U-R-L」と読めるからだ。ただしラウンドトリップ性は失われる。

Python の PEP 8 は名目上は単語として扱う流派を推奨するが、Python の標準ライブラリは歴史的に一貫性を欠く。http.server.HTTPServerxml.etree.ElementTree は頭字語を保持し、json.JSONDecoder も同じだ。新しい追加(pathlib.PurePathdataclasses)は単語として扱う側に寄っている。PEP 8 の主旨は「周囲のコードに従え」だ。

2026 年初頭の GitHub 公開コーパス(BigQuery bigquery-public-data.github_repos のサンプルを、スター 1k 以上のリポジトリの TypeScript と JavaScript ファイルに絞ったもの)をスポットチェックすると、parseUrlparseURL の比率はおおよそ 7:3、userIduserID の比率は 6:4 となる。JavaScript では単語として扱う流派が優位だ。C# は Microsoft 流が圧倒的で、parseURL が C# ファイルで支配的だ。Python は真っ二つに割れている。

意思決定ルール:(a) いま書いている言語の標準ライブラリに従う。(b) 標準ライブラリが一貫していない場合、新規プロジェクトでは単語として扱う流派を選ぶ。ラウンドトリップが通るからだ。(c) その選択を linter またはスタイル設定に書き込み、一つのプロジェクト内では混ぜない。ケース変換ツールのトークナイザーは lodash と change-case パッケージに合わせて単語として扱う慣習に従う。XMLHttpRequest を貼り付ければ、camelCase、snake_case、kebab-case の出力としてそれぞれ xmlHttpRequestxml_http_requestxml-http-request が返る。

URL スラッグ: なぜ kebab-case が snake_case に勝つのか

URL 構造に関する Google 公式の Search Central ドキュメントには、具体的な case の推奨が一つある。URL では単語の区切りにハイフンを使い、アンダースコアを使うな、というものだ。理由はトークン化にある。Google の検索インデックスは URL をハイフンで分割するがアンダースコアでは分割しない。https://example.com/buy-running-shoesbuyrunningshoes の 3 つのインデックス可能な語にトークン化され、これらのいずれにもマッチできる。https://example.com/buy_running_shoesbuy_running_shoes という単一の語としてトークン化され、その文字列に完全一致するクエリにしかマッチしない。

ランキングへの影響は、確立されたページでは小さい(Google は他のシグナルも持つ)が、競合の多い SERP に挑む新しいページでは効いてくる。同点のページでは kebab-case の URL が上位に来る。

もう一つ理由がある。大文字小文字の区別だ。URL パスは Linux サーバー(Web の大部分)では大文字小文字を区別する。/User-Profile/user-profile は別の URL であり、別のキャッシュエントリ、別のアナリティクス行になる。小文字の kebab-case は「Mac では動くのに」というバグを招かない綴りだ。

タイトルから kebab-case スラッグを作る 4 ステップのレシピを示す。

  1. すべて小文字にする。
  2. 連続する空白と句読点を 1 つのハイフンに置き換える。
  3. 先頭と末尾のハイフンを取り除く。
  4. 必要ならストップワード(aantheoffor)を落とす。短い URL にしたい場合のみで、CMS がページ見出し用に元のタイトルを保持しているときに限る。

例:"10 Tips for Faster JavaScript: A Complete Guide"10-tips-faster-javascript-complete-guide。コロンとストップワード(fora)を除去し、結果は 39 文字。SERP 表示のスイートスポットである 50-60 文字を下回る。URL の長さとプラットフォーム固有の文字数制限の関係については、文字数・単語数の制限ガイドを参照。

ケース変換ツールは、任意のタイトルを貼り付ければ kebab-case 出力を返す。CMS 移行やサイトマップ生成でスラッグを大量に作るときに役立つ。

6 つの変換落とし穴

case 間の自動変換は些細な作業に見えるが、そうではない。壊れる場所が 6 つある。

1. 数字と文字の境界

file2x を snake_case に変換するとどうなるか。主流の慣習(lodash、change-case、PEP 8、ケース変換ツール)は文字と数字の遷移をすべてトークン境界として扱う。よって file2xfile / 2 / x になり、snake_case では file_2_x だ。parseUTF8parse / utf / 8 になり、parse_utf_8 となる。

古いライブラリ(および Stack Overflow で見つかる手書きの re.sub スニペット)にはこのルールを無視し、file2xfile2xparseutf8 を生成するものがある。ミスマッチはライブラリ間でコードを移行したときに顕在化し、症状は「識別子の半分はリネームされ、もう半分はされなかった」だ。トークナイザーを 1 つ選び、数字境界ルールに従うことを確認して貫く。

2. 連続する大文字

頭字語境界の正規表現は /([A-Z]+)([A-Z][a-z])/ だ。連続する大文字と、新しい単語を始める最後の大文字との間を分割する。XMLHttpRequestXML + HttpRequest にマッチし、さらに Http + Request にマッチして、トークンは XML / Http / Request になる。

問題は逆方向だ。XML / Http / Request を PascalCase に戻すと XmlHttpRequest になる。XMLHttpRequest にはならない。頭字語がタイトルケースになる。これが標準の挙動だ。代替案、つまり「どのトークンがもともと頭字語だったか」を覚えておくには、トークナイザーが持たないアウトバンドのメタデータが要る。コードベースが XMLHttpRequest 流で、プロジェクト全体のリネームを単語として扱うコンバーターで走らせると、すべての頭字語を黙って書き換える。先にブランチでテストするか、頭字語を明示的にマークできるトークナイザーを使う。

3. Unicode とロケール対応の case マッピング

JavaScript の 'I'.toLowerCase() は通常 'i' を返す。同じ呼び出しをトルコ語ロケールで実行すると 'ı'(点なし i、U+0131)を返す。トルコ語には 2 種類の i があり、大文字 I の小文字は点なしのほうだからだ。このバグは多くの国際化対応リリースに紛れ込んできた。比較のためにユーザー名を大文字化するログインフォームが、İrem という名前のトルコ語ロケールユーザーを黙ってロックアウトする。

地雷はあと 2 つある。ドイツ語の ß.toUpperCase()'SS' を返す。1 文字が 2 文字になるので、case 変換が文字列の長さを保つと仮定するコードはすべて間違いだ。ギリシャ語の Σ.toLowerCase() はコンテキスト依存で、単語の途中なら σ、末尾なら ς になる。

対策:toLocaleLowerCase()toLocaleUpperCase() を明示的なロケール引数付きで使う。ユーザーのロケールが分からない場合は 'en-US' を渡して ASCII 互換の挙動を得る。ケース変換ツールは Intl 対応のメソッドを使うので、これら 3 つの入力すべてを正しく扱える。正規表現側は 正規表現チートシート\p{L} の Unicode 文字クラスを扱う。

4. スマートクォート汚染

Microsoft Word、Google Docs、macOS のメモから文字列を case コンバーターに貼り付けると、目に見えない文字が紛れ込むことがある。U+2018 / U+2019 / U+201C / U+201D(カーリークォート)、U+2014(em ダッシュ)、U+00A0(ノンブレーキングスペース)、U+200B(ゼロ幅スペース)。これらはほとんどのフォントで ASCII の同等物と見分けがつかないが、エンコーディングは違う。U+00A0 を含む camelCase 識別子は言語によってはコンパイルが通ったり通らなかったりし、変数名を grep してもその出現を取りこぼす。

対策:トークン化する前に入力を正規化する。1 行の input.normalize('NFKC').replace(/[“”‘’]/g, '"') でほとんどの混入を除去できる。あるいは テキスト比較ツールガイドの手法を使う。怪しい文字列を視覚的に同じに見える ASCII の双子と diff にかけ、hex ビューで不可視文字を見つける。

5. URL を snake_case 化してはいけない

https://example.com/api/users を snake_case コンバーターに貼り付けると https_example_com_api_users が出てくる。技術的には正当な snake_case 識別子だが、意味論的には壊れている。URL はすでに canonical な case(小文字 kebab-case のパスセグメントを持つ path/case)であり、URL 全体を 1 つの識別子として扱うと構造情報が失われる。

対処は、URL をパースしてパスセグメントを取り出し、必要ならセグメントごとに変換することだ。ケース変換ツールが URL を自動でパースしないのは意図的な設計だ。ユーザーの意図を推測するほうが、文字どおりに扱うよりも危ない。URL を貼り付ければ文字どおりの変換が返る。セグメント単位の挙動が必要なら、自分で前処理する。

6. dot.case とプロパティアクセス

文字列 user.profile.image はコンテキストで意味が変わる。TOML ファイル中の dot.case 識別子なら、3 つのセグメントを持つ 1 つの名前だ。JavaScript の式なら、userprofile プロパティの image プロパティだ。

設定ファイルから dot.case 文字列をコピーして JavaScript コンソールに貼り付けると、ランタイムはそれをプロパティ連鎖として評価しようとし、エラーを返すか思わぬ値を返す。逆に、JS のプロパティパスを文字列操作するコード('a.b.c'.split('.'))が別の場所から来た dot.case 識別子を受け取り、想定より深いパスとして扱うこともある。両者は名前空間を分けて運用する必要がある。

慣習:dot.case 文字列はデータ(設定ファイル、MongoDB パス、ログのキー)の中に閉じ込める。単一識別子のコードは camelCase または snake_case を使う。コード中で階層構造が必要なら、ネストしたオブジェクトとホスト言語の dot プロパティ構文を使う。

言語横断の移行レシピ

JS の camelCase から Python の snake_case へ

最速のワークフローは、JS の識別子をコピーしてコンバーターに貼り付け、snake_case 出力をコピーすることだ。コードレベルで一括変換する場合は次のようにする。

import { snakeCase } from 'change-case';

snakeCase('parseHTML');         // 'parse_html'
snakeCase('XMLHttpRequest');    // 'xml_http_request'
snakeCase('parseUTF8');         // 'parse_utf_8'
snakeCase('iPhone');            // 'i_phone'

最後の例が落とし穴だ。iPhone はブランド名で、camelCase の境界判定が誤解を招く。ブランド名や一握りの歴史的識別子は、変換後に手で直す。

SQL の snake_case から JS / Java の API レスポンスへ

ほとんどの ORM はこれを自動でやってくれる。Sequelize には underscored: true がある。TypeORM には SnakeNamingStrategy クラスがある。Hibernate には ImplicitNamingStrategyComponentPathImpl がある。デフォルトのマッピングは user_profile_iduserProfileId だ。

破綻するのは頭字語を含むカラムだ。http_status_code というカラムは httpStatusCode にラウンドトリップするが、コードベースが HTTPStatusCode を好む場合、ORM はそちらに従わない。カラム名を httpstatuscode_code にリネームするか(醜い)、ORM に頭字語を保持するよう設定するか(まれ)、標準の慣習を受け入れるかだ。

React の PascalCase コンポーネントから CSS の kebab-case クラスへ

// UserProfileCard.tsx
export function UserProfileCard({ user }) {
  return <div className="user-profile-card">{user.name}</div>;
}
/* UserProfileCard.module.css */
.user-profile-card { padding: 1rem; }
.user-profile-card__avatar { border-radius: 50%; }
.user-profile-card--featured { background: gold; }

BEM(Block Element Modifier)は React と組み合わせる CSS クラス慣習で最も一般的だ。ブロックは kebab-case のコンポーネント名、要素は block__element、修飾子は block--modifier となる。ファイルレベルでは、コンポーネントは UserProfileCard.tsx、スコープ付きスタイルは UserProfileCard.module.css というように、両方とも PascalCase でコンポーネント名に合わせる。

環境変数からアプリケーション設定へ

# .env (CONSTANT_CASE)
DATABASE_URL=postgres://localhost/myapp
MAX_RETRIES=3
LOG_LEVEL=info
// Node.js
const dbUrl = process.env.DATABASE_URL;
const maxRetries = parseInt(process.env.MAX_RETRIES, 10);
# Python
import os
db_url = os.environ['DATABASE_URL']
max_retries = int(os.environ['MAX_RETRIES'])

環境変数の名前は CONSTANT_CASE のままにし、アプリケーション側の識別子は言語の変数慣習に従う。YAML / TOML の設定キーは慣習として snake_case(database_urlmax_retries)で、ランタイムでは同じ CONSTANT_CASE の環境変数にマッピングされる。Spring、dotenv、Pydantic などのフレームワークが case のマッピングを処理する。

ライブラリとツールの比較

ツール言語サポートする caseトークナイザーの挙動
lodash (_.camelCase ほか)JavaScript主要 4 種 + startCase頭字語を単語として扱う
change-case npm パッケージJavaScript/TSプログラミング用 8 種すべて頭字語を単語として扱う
inflection(Python)PythoncamelCase / snake_case頭字語を単語として扱う
convert_case クレートRust12 種以上頭字語を設定可能
Go の strings + 正規表現Go手書きプロジェクト定義
VS Code(組み込み)エディタUPPER / lower / Title のみ空白のみ
VS Code「change-case」拡張エディタプログラミング用 8 種すべて頭字語を単語として扱う
ケース変換ツールブラウザ15 種(テキスト 7 + コード 8)頭字語を単語として扱う

日々のコーディングでは change-case(JS)か convert_case(Rust)を入れておくとよい。Python なら inflection パッケージが定番だが、手書きの正規表現でも 90% のケースをカバーできる。コードレビューやリファクタリング中の単発変換には、ケース変換ツールが 15 種類の出力を一度に表示する。トークン数を数えたり識別子の長さを検証するなら 文字数カウンター、トークナイザーの正規表現を検証するなら上記のチートシートのパターンと併せて 正規表現テスターを使う。

FAQ

camelCase と PascalCase の違いは何か

camelCase は小文字で始まる(userProfile)。PascalCase は大文字で始まる(UserProfile)。どちらもそれ以降の単語の先頭を大文字にし、区切り文字を持たない。camelCase は多くの C 系言語で変数と関数に使い、PascalCase はクラス、型、React コンポーネントに使う。

なぜ Python は snake_case を使い JavaScript は camelCase を使うのか

Python(1991 年)は C と ABC 言語から snake_case を受け継ぎ、PEP 8 がコミュニティ標準として定式化した。JavaScript(1995 年)は Java の camelCase 流を踏襲し、Java は Smalltalk の camelCase を継承していた。どちらも歴史的な経路依存だ。どちらの慣習が技術的に優れているということはない。可読性の研究はほぼ互角で、選択そのものよりエコシステム内で一貫させることのほうが重要だ。

camelCase の頭字語は parseUrl と parseURL のどちらを使うべきか

parseUrl(頭字語を単語として扱う)はモダンなデフォルトだ。Google、Apple、lodash、change-case npm パッケージが採用する。parseURL(頭字語の大文字を保持)は Microsoft の .NET 流で、C# コードで支配的だ。JavaScript、TypeScript、Swift の新規プロジェクトなら parseUrl を選ぶ。snake_case と kebab-case の変換をラウンドトリップできるからだ。どちらを選ぶにせよ、linter に書き込む。

URL では kebab-case のほうが snake_case より優れているのか

優れている。Google 公式の Search Central ガイダンスは、URL でアンダースコアではなくハイフンを使うよう指示している。検索インデクサはハイフンをトークン区切りとして扱うが、アンダースコアは扱わない。/user-profileuser + profile としてインデックスされるが、/user_profileuser_profile という単一の語としてインデックスされる。ページごとのランキングへの影響は小さいが確かに存在し、小文字 kebab-case の URL は Linux サーバーでの大文字小文字バグも防げる。

データベースのカラム名はどの case を使うべきか

snake_case を使う。主要 ORM(SQLAlchemy、Hibernate、Sequelize、TypeORM、Active Record)がデフォルトでこれを採用し、主要 SQL 方言が同じように扱う。PostgreSQL は引用符なし識別子を小文字に畳み込み、MySQL は Linux で大文字小文字を区別し macOS / Windows では区別せず、SQLite は名前を不透明に扱う。小文字 snake_case はどこでも同じ挙動になる綴りだ。

1 つのプロジェクトで複数の命名規則を混ぜてよいか

よい — そしてたいてい混ぜざるを得ない。典型的な Web アプリは JS 変数に camelCase、データベースに snake_case、CSS クラスと URL に kebab-case、環境変数に CONSTANT_CASE を使う。ルールは「レイヤーごとに 1 つの慣習、レイヤー内では混ぜない」だ。レイヤーごとの選択を linter かスタイルガイドに書き込み、PR レビューでそれが議題にならないようにする。

case 間をプログラムから変換するにはどうすればよいか

JavaScript と TypeScript では change-case を入れるか、lodash の _.camelCase / _.snakeCase / _.kebabCase を使う。Python では inflection パッケージ、または短い正規表現(PascalCase から snake_case への re.sub(r'(?<!^)(?=[A-Z])', '_', s).lower())。Rust では convert_case クレート。単発のインタラクティブな変換には、ケース変換ツールが任意の入力に対して 15 種類の case 出力を 1 つのブラウザページで表示する。

CONSTANT_CASE は環境変数だけのためのものか

いや、環境変数が最も一般的な用途だが、それに限らない。CONSTANT_CASE は「実行時不変量」のすべてに使う。MAX_RETRIESAPI_BASE_URLDEFAULT_PAGE_SIZE、enum 値、マクロ定義、トップレベルの設定定数などだ。ルールは「これを実行時に変えたらバグになるか」。なるなら CONSTANT_CASE、ならないなら言語の通常の変数慣習を使う。const result = await fetch(url) はそのままで構わない。

dot.case と path/case の違いは何か

dot.case は . を区切り文字に使い(user.profile.image)、データ内の階層キーを表す。Java パッケージ、MongoDB フィールドパス、TOML 設定キー、Lodash の get/set パスなど。path/case は / を使い(user/profile/image)、実際の場所を表す。URL パス、ファイルシステムパス、Git の ref など。ドットとスラッシュの選択は「データのラベル」と「実際の場所」を区別するシグナルになる。

30 秒の意思決定シート

質問の 95% をカバーする 3 つのルール。

  1. コード識別子は、その言語の標準ライブラリに合わせる。 Python:変数と関数は snake_case、クラスは PascalCase。JavaScript と TypeScript:変数と関数は camelCase、クラスとコンポーネントは PascalCase。Go:パッケージプライベートは先頭小文字、エクスポートは先頭大文字。Rust:変数と関数は snake_case、型は PascalCase、定数は SCREAMING_SNAKE。

  2. 横断レイヤーは言語に関係なく case が固定されている。 URL は kebab-case。CSS クラスは kebab-case。データベースのカラム名は snake_case。環境変数は CONSTANT_CASE。HTTP/1.1 ヘッダーは Header-Case(HTTP/2 はワイヤ上で小文字に正規化する)。

  3. 選択を linter に一度書き込んで議論をやめる。 ESLint、Pylint、Clippy、golangci-lint、Rubocop はすべてこのためのルールを持つ。慣習を選んで linter を設定すれば、次の PR レビューは userIDuserId の議論に一語も費やさない。

case を変換する必要があるとき — リファクタリング、CMS 移行、SQL から API へのマッピング — には、ケース変換ツールが 1 回の貼り付けで 15 種類の case 出力を返す。手作業でトークン化することなく、正しいものをコピーできる。関連するテキスト作業については、文字数カウンター正規表現テスターテキスト比較・差分ツールも参照。深堀りしたい場合は、正規表現チートシートがトークナイザーのパターンを、テキスト比較ツールガイドが移行中の before/after 比較を、文字数・単語数の制限ガイドが SEO スラッグの URL 長予算を扱う。