diff --git a/.gitarchive b/.gitarchive
new file mode 100644
index 0000000000000000000000000000000000000000..3994ec0a83ea6af834f1e4cbd644435eb2168888
--- /dev/null
+++ b/.gitarchive
@@ -0,0 +1,4 @@
+node: $Format:%H$
+node-date: $Format:%cI$
+describe-name: $Format:%(describe:tags=true)$
+ref-names: $Format:%D$
diff --git a/.gitattributes b/.gitattributes
index 2f88ca8bc7da8f19d27ef6c68450d91b15067625..4174c2c11802378444130abb951faf7df71ac9b6 100755
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,4 @@
+.gitarchive  export-subst
 tests/keplerian-orbits-1-0-2.h5 filter=lfs diff=lfs merge=lfs -text
 tests/esa-orbits-1-0-2.h5 filter=lfs diff=lfs merge=lfs -text
 tests/keplerian-orbits-2-0.h5 filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2ade3044733bbf20e20fe87a13c1566a7365dc49..99bfb4e8503464d73ddca90c551d7b83cbdfc126 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,12 +4,18 @@ image: python:3.8
 
 stages:
   - test
-  - generate
+  - document
+  - build
+  - deploy
 
 before_script:
   - pip install -r requirements.txt
   - pip install .
 
+cache:
+  paths:
+    - public
+
 pylint:
   script:
     - pylint lisainstrument
@@ -20,3 +26,23 @@ pytest:
   artifacts:
     reports:
       junit: report.xml
+
+dist:
+  stage: build
+  script:
+    - python -m build
+  rules:
+    - if: '$CI_COMMIT_TAG =~ /^v\d+(?:\.\d+){0,2}$/'
+  artifacts:
+    paths:
+      - dist
+
+pypi:
+  stage: deploy
+  script:
+    - twine check dist/*
+    - twine upload dist/*
+  dependencies:
+    - dist
+  rules:
+    - if: '$CI_COMMIT_TAG =~ /^v\d+(?:\.\d+){0,2}$/'
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..27cbd39b7afeff08b86e3a8b4b8bde9cb1ef30f6
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
+prune docs
+prune tests
+exclude .*
+exclude requirements.txt
+exclude zenodo.py
diff --git a/lisainstrument/__init__.py b/lisainstrument/__init__.py
index 85367f1c831bc964cf326794bae0676c50ef3dd3..26425295c33b68e23c8d948cc33f6d5dbd0c5d0a 100644
--- a/lisainstrument/__init__.py
+++ b/lisainstrument/__init__.py
@@ -2,9 +2,16 @@
 # -*- coding: utf-8 -*-
 """LISA Instrument module."""
 
-from .meta import __version__
-from .meta import __author__
-from .meta import __email__
+import importlib_metadata
 
 from .instrument import Instrument
 from .hexagon import Hexagon
+
+
+try:
+    metadata = importlib_metadata.metadata('lisainstrument').json
+    __version__ = importlib_metadata.version('lisainstrument')
+    __author__ = metadata['author']
+    __email__ = metadata['author_email']
+except importlib_metadata.PackageNotFoundError:
+    pass
diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py
index 90105c5f1402049c651eb689467014ba56e4fa10..75d8d74fc3eb14bbd470cf343aa4d68496da5111 100755
--- a/lisainstrument/instrument.py
+++ b/lisainstrument/instrument.py
@@ -12,6 +12,7 @@ import re
 import logging
 import numpy as np
 import matplotlib.pyplot as plt
+import importlib_metadata
 
 from h5py import File
 from scipy.signal import lfilter, kaiserord, firwin
@@ -25,7 +26,6 @@ from lisaconstants import c
 from .containers import ForEachSC
 from .containers import ForEachMOSA
 
-from . import meta
 from . import dsp
 from . import noises
 
@@ -181,7 +181,7 @@ class Instrument:
         # pylint: disable=too-many-arguments,too-many-statements,too-many-locals,too-many-branches
         logger.info("Initializing instrumental simulation")
         self.git_url = 'https://gitlab.in2p3.fr/lisa-simulation/instrument'
-        self.version = meta.__version__
+        self.version = importlib_metadata.version('lisainstrument')
         self.simulated = False
 
         # Check orbit dataset
diff --git a/lisainstrument/meta.py b/lisainstrument/meta.py
deleted file mode 100644
index 18c7e94615bf1e3c0257dfa7950232b26806a7b3..0000000000000000000000000000000000000000
--- a/lisainstrument/meta.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#! /usr/bin/env python3
-# -*- coding: utf-8 -*-
-# pylint: disable=missing-module-docstring
-
-__version__ = '1.2.dev'
-__author__ = 'Jean-Baptiste Bayle'
-__email__ = 'j2b.bayle@gmail.com'
diff --git a/requirements.txt b/requirements.txt
index 7eec399b403a94fbcbeea1d4a627cd5c0aca9faa..23213a1c226d7a66c236bb2e68343e7114b3e5ec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,6 +13,7 @@ bleach==5.0.0
 certifi==2021.10.8
 cffi==1.15.0
 charset-normalizer==2.0.12
+commonmark==0.9.1
 cycler==0.11.0
 debugpy==1.6.0
 decorator==5.1.1
@@ -23,7 +24,7 @@ entrypoints==0.4
 executing==0.8.3
 fastjsonschema==2.15.3
 fonttools==4.31.2
-h5py==3.6.0
+h5py==3.7.0
 healpy==1.15.2
 idna==3.3
 imagesize==1.3.0
@@ -33,12 +34,14 @@ ipykernel==6.11.0
 ipython==8.2.0
 ipython-genutils==0.2.0
 isort==5.10.1
+jaraco.classes==3.2.3
 jedi==0.18.1
 Jinja2==3.1.1
 jsonschema==4.6.0
 jupyter-client==7.2.1
 jupyter-core==4.9.2
 jupyterlab-pygments==0.2.2
+keyring==23.9.3
 kiwisolver==1.4.1
 lazy-object-proxy==1.7.1
 lisaconstants==1.3
@@ -50,6 +53,7 @@ mccabe==0.7.0
 mdit-py-plugins==0.3.0
 mdurl==0.1.0
 mistune==0.8.4
+more-itertools==9.0.0
 mypy==0.961
 mypy-extensions==0.4.3
 myst-parser==0.17.0
@@ -58,13 +62,14 @@ nbconvert==6.5.0
 nbformat==5.4.0
 nest-asyncio==1.5.4
 notebook==6.4.12
-numpy==1.22.3
+numpy==1.23.4
 packaging==21.3
 pandocfilters==1.5.0
 parso==0.8.3
 pexpect==4.8.0
 pickleshare==0.7.5
 Pillow==9.0.1
+pkginfo==1.8.3
 platformdirs==2.5.1
 pluggy==1.0.0
 prometheus-client==0.14.1
@@ -84,9 +89,14 @@ python-dateutil==2.8.2
 pytz==2022.1
 PyYAML==6.0
 pyzmq==22.3.0
+readme-renderer==37.2
 requests==2.27.1
+requests-toolbelt==0.10.0
+rfc3986==2.0.0
+rich==12.6.0
 scipy==1.8.0
 Send2Trash==1.8.0
+setuptools-scm==7.0.5
 six==1.16.0
 snowballstemmer==2.2.0
 soupsieve==2.3.2.post1
@@ -105,6 +115,7 @@ tomli==2.0.1
 tomlkit==0.11.0
 tornado==6.1
 traitlets==5.2.2.post1
+twine==4.0.1
 typing_extensions==4.1.1
 urllib3==1.26.9
 wcwidth==0.2.5
diff --git a/setup.py b/setup.py
index bffce83a0d87ad0e3b62c84b4cc9dbbcd568409f..ded2824eb1653f839408cd3b0513d8ba557a662f 100644
--- a/setup.py
+++ b/setup.py
@@ -2,26 +2,23 @@
 # -*- coding: utf-8 -*-
 # pylint: disable=line-too-long,missing-module-docstring,exec-used
 
-from typing import Dict
 import setuptools
 
 
 with open("README.md", 'r', encoding='utf-8') as fh:
     long_description = fh.read()
 
-META: Dict[str, str] = {}
-with open("lisainstrument/meta.py", 'r', encoding='utf-8') as file:
-    exec(file.read(), META)
 
 setuptools.setup(
     name='lisainstrument',
-    version=META['__version__'],
-    author=META['__author__'],
-    author_email=META['__email__'],
+    use_scm_version=True,
+    author='Jean-Baptiste Bayle',
+    author_email='j2b.bayle@gmail.com',
     description='LISA Instrument simulates instrumental noises, propagates laser beams, generates measurements and the on-board processing to deliver simulated telemetry data.',
     long_description=long_description,
     long_description_content_type="text/markdown",
     url="https://gitlab.in2p3.fr/lisa-simulation/instrument",
+    license='BSD-3-Clause',
     packages=setuptools.find_packages(),
     install_requires=[
         'h5py',
@@ -30,7 +27,9 @@ setuptools.setup(
         'matplotlib',
         'lisaconstants',
         'packaging',
+        'importlib_metadata',
     ],
+    setup_requires=['setuptools_scm'],
     tests_require=['pytest'],
     python_requires='>=3.7',
 )