This is actually a fairly crucial matter, since relative paths definitely won't work with languages, unless you really want all assets in a given Source to be localized or at least copied to each language folder. As well, hard paths in the CP will fail with multi-environment config where dev, staging, and deployment sites can have different full storage paths.

Things may appear to operate at first with relative paths, for example, and it may feel like a safe way from experience with other systems, but then you'll find that features like automatic generation of image transforms that you've set up (icons, controlled sizes, etc.) will fail.

3 Answers 3


If each locale uses the same TLD but uses a subfolder for localized content (i.e. example.com/en, example.com/de, etc.). You can move between development, staging, and production environments without having to change settings in the admin panel by simply using an absolute path in the Admin assets source URL setting (i.e. /assets/img/uploads) and a relative path for the File System Path there (i.e. ../public_html/assets/img/uploads).

For more complicated setups, such as independent site URLs (i.e. example.com, example.co.uk, etc) for each locale, I've set asset paths by setting an assetsUrl environment variable in general.php like so:

'example.com' => array(
    'environmentVariables' => array(
        'siteUrl'        => '//example.co.uk/',
        'assetsUrl'    => '//example.com/'

Then in the Admin panel's assets source settings, I set a relative path for the File System Path and use the {assetsUrl} environment variable for the URL.

Screenshot of Craft Assets Source Settings

With this setup you can also move between development, staging, and production environments without having to change settings in the admin panel.

Once {assetsUrl} is set in the Admin panel for the URL, writing {{ file.url }} in your template will return the full URL using the assets source URL setting.

Or, you can link to assets (e.g. scripts) in your templates using the assetsUrl environment variable.

{{ craft.config.environmentVariables['assetsUrl'] }}assets/js/main.js
  • Good point about when you actually do want to use per-language customized assets. Jun 12, 2014 at 3:53
  • (Nasty comment system here, cuts off thought) continuing: Your ../ style server paths are however only going to work for that case, if they do, as they are going to be relative to the language folder where the index.php is called. Have you verified that transforms are indeed successfully generated, and for all kinds of assets, language-specific or not? The other issue will be actual server folder layout, and possible open_basedir restrictions... Jun 12, 2014 at 4:17
  • I've added your case to the original question, for its uses, and would suggest that the usual non-localized assets should use the original answer, while for necessarily localized assets, with care to server circumstances and verification, your relative references can be useful. To cover both cases, you'd define each type of asset in their own Craft Asset Source. Jun 12, 2014 at 5:41
  • @narration_sd if I am getting this right, Stephens answer to use relative path notation for the File System Path has nothing to do with localized assets. It is just a simple way to link to the same folder from each locales subfolder (i.e. example.com/de).
    – carlcs
    Jun 12, 2014 at 8:16
  • Christian, you're correct, to the point. I was mistaken in late evening by Stephen referring to localized content, but indeed it's centralized content which would operate with site localization that he's pathed. However, I've just tested and confirmed that this ../ pathing does not fully work. Asset indexing in the main CP icon panel reports the path is mis-set, and I think this also interrupts further indexing, so that for my case S3 assets aren't set up as well, unless they perhaps were so previously. Craft will tell you to use full paths as in the other solution, and there are reasons... Jun 12, 2014 at 20:24

An answer that works is to make your own environment variables, setting those apart from language variables, and as needed for each of your multiple sites.

Then you can use these variables to make full paths for your Asset definitions.

You'll need definitions for both the file system path and URL path. Let's name them appropriately so we don't get confused with {siteUrl}, which is common in a multilingual config or {{siteUrl}} which is the Twig variable resulting from whatever sets it for a given Craft site for templates, but not usable within CP configuration.

Here's an example config:

return array( 'cpTrigger' => 'yourTrigger', 'environmentVariables' => array( 'siteStore' => '/storage/yourId/www/yoursite_html/', 'sitePath' => 'http://yoursite.com/', ), 'siteUrl' => array( 'en' => 'http://yoursite.com/en/', 'de' => 'http://yoursite.com/de/', 'fi' => 'http://yoursite.com/fi/', ), );

In the CP on a multi-language site, we'd fill in Assets->Sources->Local Images->File System path as:


And to match, the URL would be set to:


With this, your paths for images and their generated transforms will be stable and correct across languages as well as the default URL.

To extend across multiple development, staging, and live sites, you'd just replicate this extra config in the usual way, filling in suitable siteStore and sitePath values for each environment.

  • Ok, had to change the comment here, as though I appreciate Stephen's thought, it does turn out apparently to not work, details commented there. This is not exactly a surprise having traced the code in this area when I wanted to use relative paths also, and by matching Craftpersons' advice. Still interested, though, as there are aspects which haven't been covered. I think these will make another interesting Craft SE question... Jun 12, 2014 at 20:44
  • Ok, I've looked over this very carefully before checking this solution as the accepted one, and it will take more than one comment to explain that. I too wanted all-relative paths to work; it's how I found the problems, and I appreciate that a lot of favoriting of Stephen's proposal occurred because of this desire. However, I am pretty confident it just can't work at the present in Craft. It may appear to. Relative paths can indeed be correct for the Asset URL path. But relative paths can't work for the Asset File System path, because they will not be correct for transformed image generation. Jun 14, 2014 at 7:02
  • This means that when you have icons, reduced sizes, etc. as transforms, i a Locale-activated system their assets won't be generated. You may think they have been if you earlier used non-localized setup, as the files will be left from that. But if you clear them, by the CP button and by removing asset cache and site assets _name subdirectories for them, you'll find they will only regenerate if you have an absolute path for the File System Path. It's how Craft operates at present. Jun 14, 2014 at 7:11
  • Ok, my 'I think you'll find/as far as I know' edits were zapped by this timeout comment system, but you may assume them, please. To return to the issue of the URL path, yes, it can be made root-relative (/resources/images) instead of {SitePath}resources/images in the Asset definition form, if you keep it consistent between site rather than language variations, and want to go that way. I think I've come over to the full-path-everywhere point of view, after a lot of fiddling with otherwise, unless the Craft crew may change the situation, probably as they may be adding features. Cheers to all. Jun 14, 2014 at 7:26
  • And - of course there is one more thought, from that handy off-line engine where we get ideas. If it proves out, great, and then I would really wish to be able to check two answers. 'Correct' is generally a fallacy; usually it's works in this case, and/or works in that. We'll see if that's true here. Jun 14, 2014 at 8:25

Great answer above: https://craftcms.stackexchange.com/a/30/1056 Works like a charm.

But for multiple environments it can get pretty nasty to set up the file system for each environment individually. This is what I did to figure out the correct file system path:

return array(
    '*' => array(
        'environmentVariables' => array(
            'assetsPath' => realpath(__DIR__ . '/../../public/assets')

The config path never changes, so it’s a good way to use it to figure out the assets path.

Watch out: For PHP < 5.3 it has to be

'assetsPath' => realpath(dirname(__FILE__) . '/../../public/assets')
  • 1
    I like it :) There's another method using environmental tags you set in the index.php which is bulletproof, but to extent this reliably functions, automation is great. Nice you've picked up the PHP level it needs to adjust to. Nice also to update this post, which is by now getting a bit 'properly aged'...people will find your answer here, upvoted. May 23, 2017 at 9:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.