Symlinks¶
A symlink (symbolic link) is a shortcut stored inside your site that points to another file or directory. When a visitor navigates to the symlink path, they see the content of the target automatically. This is useful for publishing "latest" pointers that always resolve to the most recent version of a file or folder.
When to use symlinks¶
- Expose the latest release of a dataset at a fixed, well-known URL (e.g.,
/data/latest→/data/2026-03-16/). - Create an alias for a long path that is easier to share.
- Redirect one location in your site to content that lives elsewhere within the same site.
Getting a content manager¶
Symlink operations require a SiteContentManagement instance:
from sites.sdk.sites import Site, Authenticator
site = Site.from_space_and_name(space='docs', name='my-project')
content_manager = site.get_content_manager(
authenticator=Authenticator.from_token(token='<admin_site_bearer_token>')
)
Creating a symlink¶
result = content_manager.create_symlink(
path='/data/latest', # the symlink path (what visitors access)
target_path='/data/2026-03-16/' # where the symlink points within the site
)
print(result)
Both path and target_path are paths within your site's file system (not full URLs).
Overwrite an existing symlink¶
If a symlink already exists at path you will get an error by default. Use force=True to replace it:
# Update the 'latest' symlink to point at a new folder
content_manager.create_symlink(
path='/data/latest',
target_path='/data/2026-04-01/',
force=True # overwrites the existing symlink
)
Reading a symlink¶
To check what a symlink points to:
info = content_manager.get_symlink(path='/data/latest')
print(info)
# {'target': '/data/2026-03-16/'}
The returned dict contains a target key with the path the symlink resolves to.
Deleting a symlink¶
result = content_manager.delete_symlink(path='/data/latest')
print(result)
# {'status': 'OK', 'message': 'Symlink deleted.'}
If the symlink does not exist, a FileNotFoundError is raised.
Use force=True to force deletion even if there are edge cases the server would normally reject:
End-to-end example: rotating a "latest" pointer¶
The following pattern is common for datasets published on a regular schedule:
from datetime import date
from sites.sdk.sites import Site, Authenticator
from sites.sdk.common import ApiCallException
site = Site.from_space_and_name(space='data', name='climate-archive')
mgr = site.get_content_manager(
authenticator=Authenticator.from_token(token='<admin_site_bearer_token>')
)
today = date.today().isoformat() # e.g., '2026-03-16'
new_data_path = f'/releases/{today}/'
# 1. Upload today's data release
mgr.upload(local_path=f'./output/{today}/', remote_path=new_data_path, recursive=True)
# 2. Update the 'latest' symlink to point at today's release
mgr.create_symlink(
path='/releases/latest',
target_path=new_data_path,
force=True # replace yesterday's symlink
)
print(f'Published {today} as /releases/latest')
Visitors who access https://sites.ecmwf.int/data/climate-archive/releases/latest/ will now see today's data without needing to know the date-specific path.
What's next?¶
- Content Management — uploading the files that symlinks point to
- Advanced Topics — cloning sites, CORS, custom applications
- API Reference — quick method reference