Answers.Body: <p>In most cases, case-sensitivity depends on the database collation. By default, <a href="https://craftcms.com/docs/3.x/config/db-settings.html#collation" rel="nofollow noreferrer">Craft uses case insensitive collations</a> (<code>utf8_general_ci</code> or <code>utf8mb4_0900_ai_ci</code>, depending on the charset). You can change that in your <a href="https://craftcms.com/docs/3.x/config/db-settings.html#collation" rel="nofollow noreferrer">database configuration</a>. Keep in mind that if you change the collation for an existing project, it won't update existing tables automatically. You can run this console command to change all tables to the configured collation:</p>
  <pre><code>php craft db/convert-charset
  </code></pre>
  <h2>Effects of changing the collation</h2>
  <p>Using a case-sensitive collation will make ALL database queries against that table case-sensitive. This means that upper- and lower-case letters are no longer considered identical for comparison purposes. Consider a search for elements with the title <code>apple</code>. Using a case-insensitive collation, the search will find also find <code>Apple</code>, <code>APPLE</code>, or <code>aPpLe</code>. Using a case-sensitive collation, only <code>apple</code> will match that query. See <a href="https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html" rel="nofollow noreferrer">Case Sensitivity in String Searches</a> for more information.</p>
  <p>You can work around this for individual queries in multiple  – for example, by performing an individual <a href="https://dev.mysql.com/doc/refman/8.0/en/charset-collate.html" rel="nofollow noreferrer">query with a different collation</a> or casting a specific column to binary (<code>CAST(title as BINARY)</code>). Though Craft's element query interface doesn't provide fine-grained control for that and you can't modify all queries the core uses to find and display content, so that's probably not a feasible solution.</p>
  <p>Changing the collation in your database configuration and updating all tables using the command mentioned above should have the desired effect (unless Craft handles this case in a special way, which I don't think it does). That is, if the URL is stored in lower-case, the same URL with upper-case letters won't match that entry, so that URL will go to a 404 page. This <em>might</em> be different for dynamic routes defined in PHP. Those aren't stored in the database as far as I know, so it depends on how Yii2 handles those under the hood.</p>
  <p>However, changing the collation will also impact every other query – for example, your search page might work differently if searching for <code>apple</code> doesn't find an entry with the title <code>Apple</code>.</p>
  <h2>Other considerations</h2>
  <ul>
  <li>People usually don't type URLs manually, and when they do they usually type in lower-case. Instead of preventing upper-case URLs from matching with existing entries, this effort is better spent making sure all the links on your site are in lower-case and nobody in your organization is circulating URLs with upper-case letters in them.</li>
  <li>This probably won't impact SEO at all, since most services consider URL paths to be case-insensitive. If you're worried about duplicate content, a <code>&lt;link rel=&quot;canonical&quot;&gt;</code> tag pointing to the lower-case URL should solve that once and for all.</li>
  <li>There's a reason <code>_ci</code> collations are the default – in particular, you usually expect case-insensitivity for any features relating to full-text search. Instead of changing the collation and dealing with the issues that arise from that, you could also talk to your SEO people about <a href="https://en.wikipedia.org/wiki/Law_of_triviality" rel="nofollow noreferrer">bike-shedding</a>.</li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-09-17T20:12:17.150Z
Answers.Text: Thanks a lot Moritz! btw: Changing the collation of the "uri" column in the table "elements_sites" to e.g. "utf8_bin" changed the behavior immediately, not even Craft's db/convert-charset was needed (though of course I likely oversee other side effects here).
Answers.UserDisplayName: Matthias Redl-Mann
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-09-17T12:18:08.547Z
Answers.LastActivityDate: 2021-09-17T12:23:40.670Z
Answers.LastEditDate: 2021-09-17T12:23:40.670Z
Answers.UserDisplayName: MoritzLost
Answers.Body: <p>If you're worried about search engines indexing some page where someone is linking to with a different case, as mentioned by Moritz, that's what you use the canonical tag for:</p>
  <pre><code>&lt;link rel=&quot;canonical&quot; href=&quot;{{ entry.url}}&quot;&gt;
  </code></pre>
  <p>You mention the second URL in your example 404s but flipping the argument around for a moment, I'm not sure I'd <em>want</em> the ability for authors to specify the exact same URL but with different case sensitivity—that can get ugly fast, which is what would happen if you allow case sensitive URLs.</p>
  <p>However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request,  see if they match, and the take action.</p>
  <p>404 it:</p>
  <pre><code>
  {% if entry.slug != craft.app.request.segments|last %}
      {% exit 404 %}
  {%endif%}
  </code></pre>
  <p>Or do a more subtle redirect:</p>
  <pre><code>{% if entry.slug != craft.app.request.segments|last %}
     {% redirect entry.url 301 %}
  {%endif%}
  </code></pre>
  <p>As an aside if an SEO team is prioritizing this over writing content and acquiring high quality backlinks, you need to give their head a serious shake.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-09-20T08:42:40.677Z
Answers.Text: After discussion with you guys, I agree that it is probably better to be case insensitive as long as the canonical tag is ok. The opposite would be worse.
Answers.UserDisplayName: Matthias Redl-Mann
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-09-18T16:19:13.687Z
Answers.LastActivityDate: 2021-09-18T16:25:09.497Z
Answers.LastEditDate: 2021-09-18T16:25:09.497Z
Answers.UserDisplayName: RitterKnight
Answers.Body: <p>Here is a small tweak to the code offered by @RitterKnight:</p>
  <pre><code>{% if entry.slug != '__home__' and entry.slug != craft.app.request.segments|last %}
    {% redirect entry.url 301 %}
  {% endif %}
  </code></pre>
  <p>Note the reference to the homepage's slug. Without this, the homepage will not load!!</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-01-11T21:47:57.470Z
Answers.LastActivityDate: 2023-01-11T21:47:57.470Z
Answers.UserDisplayName: 4midori
Body: <p>I was just surprised when I noticed, that our Craft installation is not case sensitive with routing:</p>
  <p>E.g.</p>
  <pre><code>https://domain.com/route/to/page-with-content
  </code></pre>
  <p>delivers the same content as</p>
  <pre><code>https://domain.com/rOute/TO/page-WITH-content
  </code></pre>
  <p>Is this intended behavior? From my point of view this is simply wrong. I want the upper URL to work (as the slugs are all lowercase) and the second to 404.</p>
  <p>Can I disable this behavior? (I did not find anything).</p>
  <p>P.S.: Please do not post any redirect solutions. Thanks!</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-16T12:31:34.713Z
Comments.Text: What database collation are you using? By default, Craft uses case-insensitive collations (`utf8mb4_0900_ai_ci` for `utf8mb4`), so URL casing is ignored on the database level. Switching to a case-sensitive collation like `utf8mb4_0900_ai_cs` might solve this, though it could introduce other problems.
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-16T17:16:50.383Z
Comments.Text: Just curious as to your use case here? Most CMS including WordPress also do this. However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request,  see if they match, and then take action.
Comments.UserDisplayName: RitterKnight
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T07:51:18.140Z
Comments.Text: @MoritzLost Are you sure, that a ci collation is not capable of exactly matching lowercase to lowercase? I thought case-insensitive just means the collation is not capable of bringing the lower/upper-case characters in relation to each other, but an SQL condition WHERE xxx="something" will still never match WHERE xxx="SoMeThInG"..
Comments.UserDisplayName: Matthias Redl-Mann
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T07:52:28.217Z
Comments.Text: @RitterKnight The discussion here in our team actually started with lowercase canonical URLs being in conflict with case-independent routing. You are creating duplicate content. Just think of a normal webserver setup, where assets /img/logo.png will never match Logo.png or LOGO.PNG. Case independence is wrong, even if Wordpress does it :-)
Comments.UserDisplayName: Matthias Redl-Mann
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T08:11:36.567Z
Comments.Text: @MatthiasRedl-Mann No, case-insensitive means the opposite. Using a case-insensitive collation means the database will treat `a` and `A` as identical by default – so a search for`apple` will match `APPLE` and `aPpLe` as well. See [case sensitivity in string searches](https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html) for reference. Of course, you can still force a case-sensitive comparison by changing the collation in your query or casting some columns to binary, though I don't think Craft does that by default.
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T08:14:57.477Z
Comments.Text: @MatthiasRedl-Mann If your problem is duplicate content caused by lowercase and uppercase letters in the URL – I don't think you have to worry about that, Google is probably smart enough to handle that for you. Though to be sure you can always stick a [canonical link tag](https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls) on your page that includes only the lowercase URL.
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T10:07:59.683Z
Comments.Text: @MoritzLost we will us a canonical tag. and I'm sure, Google is smart enough. But we need to please the SEO people :-) AND I want to fix this, so I will dive deeper ...
Comments.UserDisplayName: Matthias Redl-Mann
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T10:08:52.563Z
Comments.Text: @MoritzLost OK, thanks for explaining that. I will check the collation and let you know.
Comments.UserDisplayName: Matthias Redl-Mann
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T11:15:12.330Z
Comments.Text: @MoritzLost I can now confirm that the DB collation's "_ci" is the reason for Craft not being case sensitive with routing. Do you want to post it again as an answer, so I can confirm it?
Comments.UserDisplayName: Matthias Redl-Mann
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-17T12:20:43.037Z
Comments.Text: @MatthiasRedl-Mann Sure, I've added an answer with all the info in the comments as well as my thoughts on the problem in general ^^
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-09-18T16:17:35.970Z
Comments.Text: @MatthiasRedl-Mann FWIW If the SEO team is prioritizing this over writing content and acquiring high quality backlinks, you need to give their head a shake. I bring up WordPress because if it's generally not a problem with the most popular CMS, it's not going to be a problem in Craft either. You might find [this](https://wordpress.org/support/topic/case-sensitive-urls-2/) discussion relevant.
Comments.UserDisplayName: RitterKnight
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-01-11T21:41:49.917Z
Comments.Text: Adding a note here, Google is in fact not smart enough to recognize URLs that have the wrong case--I had to employ the <link rel="canonical"...> tag as well as use the gentle redirect code provided below. After all this, hopefully Google will properly index the site.
Comments.UserDisplayName: 4midori
Tags: <url><routing><case>
Title: Craft's case-insensitive routing
ThreadText: # Craft's case-insensitive routing
  
  (Asked by: username_0 on 2021-09-16)
  
  I was just surprised when I noticed, that our Craft installation is not case sensitive with routing:
  
  E.g.
  
  ```
  https://domain.com/route/to/page-with-content
  
  ```
  
  delivers the same content as
  
  ```
  https://domain.com/rOute/TO/page-WITH-content
  
  ```
  
  Is this intended behavior? From my point of view this is simply wrong. I want the upper URL to work (as the slugs are all lowercase) and the second to 404.
  
  Can I disable this behavior? (I did not find anything).
  
  P.S.: Please do not post any redirect solutions. Thanks!
  
  **Tags:** url, routing, case
  
  > **Comments:**
  > **username_1**: What database collation are you using? By default, Craft uses case-insensitive collations (`utf8mb4_0900_ai_ci` for `utf8mb4`), so URL casing is ignored on the database level. Switching to a case-sensitive collation like `utf8mb4_0900_ai_cs` might solve this, though it could introduce other problems.  
  > **username_2**: Just curious as to your use case here? Most CMS including WordPress also do this. However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request,  see if they match, and then take action.  
  > **username_0**: @username_1 Are you sure, that a ci collation is not capable of exactly matching lowercase to lowercase? I thought case-insensitive just means the collation is not capable of bringing the lower/upper-case characters in relation to each other, but an SQL condition WHERE xxx="something" will still never match WHERE xxx="SoMeThInG"..  
  > **username_0**: @username_2 The discussion here in our team actually started with lowercase canonical URLs being in conflict with case-independent routing. You are creating duplicate content. Just think of a normal webserver setup, where assets /img/logo.png will never match Logo.png or LOGO.PNG. Case independence is wrong, even if Wordpress does it :-)  
  > **username_1**: @username_0 No, case-insensitive means the opposite. Using a case-insensitive collation means the database will treat `a` and `A` as identical by default – so a search for`apple` will match `APPLE` and `aPpLe` as well. See [case sensitivity in string searches](https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html) for reference. Of course, you can still force a case-sensitive comparison by changing the collation in your query or casting some columns to binary, though I don't think Craft does that by default.  
  > **username_1**: @username_0 If your problem is duplicate content caused by lowercase and uppercase letters in the URL – I don't think you have to worry about that, Google is probably smart enough to handle that for you. Though to be sure you can always stick a [canonical link tag](https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls) on your page that includes only the lowercase URL.  
  > **username_0**: @username_1 we will us a canonical tag. and I'm sure, Google is smart enough. But we need to please the SEO people :-) AND I want to fix this, so I will dive deeper ...  
  > **username_0**: @username_1 OK, thanks for explaining that. I will check the collation and let you know.  
  > **username_0**: @username_1 I can now confirm that the DB collation's "_ci" is the reason for Craft not being case sensitive with routing. Do you want to post it again as an answer, so I can confirm it?  
  > **username_1**: @username_0 Sure, I've added an answer with all the info in the comments as well as my thoughts on the problem in general ^^  
  > **username_2**: @username_0 FWIW If the SEO team is prioritizing this over writing content and acquiring high quality backlinks, you need to give their head a shake. I bring up WordPress because if it's generally not a problem with the most popular CMS, it's not going to be a problem in Craft either. You might find [this](https://wordpress.org/support/topic/case-sensitive-urls-2/) discussion relevant.  
  > **username_3**: Adding a note here, Google is in fact not smart enough to recognize URLs that have the wrong case--I had to employ the <link rel="canonical"...> tag as well as use the gentle redirect code provided below. After all this, hopefully Google will properly index the site.  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_1 on 2021-09-17. Score: 3 | Accepted answer
  
  In most cases, case-sensitivity depends on the database collation. By default, [Craft uses case insensitive collations](https://craftcms.com/docs/3.x/config/db-settings.html#collation) (`utf8_general_ci` or `utf8mb4_0900_ai_ci`, depending on the charset). You can change that in your [database configuration](https://craftcms.com/docs/3.x/config/db-settings.html#collation). Keep in mind that if you change the collation for an existing project, it won't update existing tables automatically. You can run this console command to change all tables to the configured collation:
  
  ```
  php craft db/convert-charset
  
  ```
  
  ## Effects of changing the collation
  
  Using a case-sensitive collation will make ALL database queries against that table case-sensitive. This means that upper- and lower-case letters are no longer considered identical for comparison purposes. Consider a search for elements with the title `apple`. Using a case-insensitive collation, the search will find also find `Apple`, `APPLE`, or `aPpLe`. Using a case-sensitive collation, only `apple` will match that query. See [Case Sensitivity in String Searches](https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html) for more information.
  
  You can work around this for individual queries in multiple – for example, by performing an individual [query with a different collation](https://dev.mysql.com/doc/refman/8.0/en/charset-collate.html) or casting a specific column to binary (`CAST(title as BINARY)`). Though Craft's element query interface doesn't provide fine-grained control for that and you can't modify all queries the core uses to find and display content, so that's probably not a feasible solution.
  
  Changing the collation in your database configuration and updating all tables using the command mentioned above should have the desired effect (unless Craft handles this case in a special way, which I don't think it does). That is, if the URL is stored in lower-case, the same URL with upper-case letters won't match that entry, so that URL will go to a 404 page. This *might* be different for dynamic routes defined in PHP. Those aren't stored in the database as far as I know, so it depends on how Yii2 handles those under the hood.
  
  However, changing the collation will also impact every other query – for example, your search page might work differently if searching for `apple` doesn't find an entry with the title `Apple`.
  
  ## Other considerations
  
  * People usually don't type URLs manually, and when they do they usually type in lower-case. Instead of preventing upper-case URLs from matching with existing entries, this effort is better spent making sure all the links on your site are in lower-case and nobody in your organization is circulating URLs with upper-case letters in them.
  * This probably won't impact SEO at all, since most services consider URL paths to be case-insensitive. If you're worried about duplicate content, a `<link rel="canonical">` tag pointing to the lower-case URL should solve that once and for all.
  * There's a reason `_ci` collations are the default – in particular, you usually expect case-insensitivity for any features relating to full-text search. Instead of changing the collation and dealing with the issues that arise from that, you could also talk to your SEO people about [bike-shedding](https://en.wikipedia.org/wiki/Law_of_triviality).
  
  > **Comments:**
  > **username_0**: Thanks a lot Moritz! btw: Changing the collation of the "uri" column in the table "elements_sites" to e.g. "utf8_bin" changed the behavior immediately, not even Craft's db/convert-charset was needed (though of course I likely oversee other side effects here).  
  
  ---
  
  ### Answer by username_2 on 2021-09-18. Score: 3
  
  If you're worried about search engines indexing some page where someone is linking to with a different case, as mentioned by Moritz, that's what you use the canonical tag for:
  
  ```
  <link rel="canonical" href="{{ entry.url}}">
  
  ```
  
  You mention the second URL in your example 404s but flipping the argument around for a moment, I'm not sure I'd *want* the ability for authors to specify the exact same URL but with different case sensitivity—that can get ugly fast, which is what would happen if you allow case sensitive URLs.
  
  However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request, see if they match, and the take action.
  
  404 it:
  
  ```
  
  {% if entry.slug != craft.app.request.segments|last %}
      {% exit 404 %}
  {%endif%}
  
  ```
  
  Or do a more subtle redirect:
  
  ```
  {% if entry.slug != craft.app.request.segments|last %}
     {% redirect entry.url 301 %}
  {%endif%}
  
  ```
  
  As an aside if an SEO team is prioritizing this over writing content and acquiring high quality backlinks, you need to give their head a serious shake.
  
  > **Comments:**
  > **username_0**: After discussion with you guys, I agree that it is probably better to be case insensitive as long as the canonical tag is ok. The opposite would be worse.  
  
  ---
  
  ### Answer by username_3 on 2023-01-11. Score: 1
  
  Here is a small tweak to the code offered by @username_2:
  
  ```
  {% if entry.slug != '__home__' and entry.slug != craft.app.request.segments|last %}
    {% redirect entry.url 301 %}
  {% endif %}
  
  ```
  
  Note the reference to the homepage's slug. Without this, the homepage will not load!!
  
  
  ---
  
  