<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>

CC BY-SA 4.0
2021-09-17T20:12:17.150Z
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).
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T12:18:08.547Z
2021-09-17T12:23:40.670Z
2021-09-17T12:23:40.670Z
MoritzLost
<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>

CC BY-SA 4.0
2021-09-20T08:42:40.677Z
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.
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-18T16:19:13.687Z
2021-09-18T16:25:09.497Z
2021-09-18T16:25:09.497Z
RitterKnight
<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>

CC BY-SA 4.0
2023-01-11T21:47:57.470Z
2023-01-11T21:47:57.470Z
4midori
<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>

CC BY-SA 4.0
2021-09-16T12:31:34.713Z
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.
MoritzLost
CC BY-SA 4.0
2021-09-16T17:16:50.383Z
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.
RitterKnight
CC BY-SA 4.0
2021-09-17T07:51:18.140Z
@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"..
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T07:52:28.217Z
@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 :-)
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T08:11:36.567Z
@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.
MoritzLost
CC BY-SA 4.0
2021-09-17T08:14:57.477Z
@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.
MoritzLost
CC BY-SA 4.0
2021-09-17T10:07:59.683Z
@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 ...
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T10:08:52.563Z
@MoritzLost OK, thanks for explaining that. I will check the collation and let you know.
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T11:15:12.330Z
@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?
Matthias Redl-Mann
CC BY-SA 4.0
2021-09-17T12:20:43.037Z
@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 ^^
MoritzLost
CC BY-SA 4.0
2021-09-18T16:17:35.970Z
@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.
RitterKnight
CC BY-SA 4.0
2023-01-11T21:41:49.917Z
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.
4midori
<url><routing><case>
Craft's case-insensitive routing
# 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**: @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"..  
> **username_0**: @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 :-)  
> **username_1**: @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.  
> **username_1**: @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.  
> **username_0**: @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 ...  
> **username_0**: @MoritzLost OK, thanks for explaining that. I will check the collation and let you know.  
> **username_0**: @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?  
> **username_1**: @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 ^^  
> **username_2**: @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.  
> **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 (utf8_general_ci or utf8mb4_0900_ai_ci, depending on the charset). You can change that in your database configuration. 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 for more information.
You can work around this for individual queries in multiple  – for example, by performing an individual query with a different collation 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  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.

> **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:


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 @RitterKnight:
{% 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!!


---

