diff --git a/packages/concordia-app/src/constants/contracts/ContractNames.js b/packages/concordia-app/src/constants/contracts/ContractNames.js
index 8ddebb5..edaef10 100644
--- a/packages/concordia-app/src/constants/contracts/ContractNames.js
+++ b/packages/concordia-app/src/constants/contracts/ContractNames.js
@@ -1,3 +1,5 @@
 export const FORUM_CONTRACT = 'Forum';
 export const POST_VOTING_CONTRACT = 'PostVoting';
 export const VOTING_CONTRACT = 'Voting';
+export const NUMBER_OF_CONTRACTS = 4;
+export const NUMBER_OF_CONTRACTS = 4;
diff --git a/packages/concordia-app/src/options/drizzleOptions.js b/packages/concordia-app/src/options/drizzleOptions.js
index 7d689ee..1323bbb 100644
--- a/packages/concordia-app/src/options/drizzleOptions.js
+++ b/packages/concordia-app/src/options/drizzleOptions.js
@@ -2,13 +2,23 @@
 import { contracts } from 'concordia-contracts';
 import web3Options from './web3Options';
 import appEvents from '../constants/contracts/events';
+import { downloadContractArtifactsSync } from '../utils/drizzleUtils';
 
 const drizzleOptions = {
   web3: web3Options,
-  contracts,
   events: { ...appEvents },
   reloadWindowOnNetworkChange: true,
   reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases
 };
 
+const CONTRACTS_SUPPLIER_URL = process.env.REACT_APP_CONTRACTS_SUPPLIER;
+
+if (!CONTRACTS_SUPPLIER_URL) {
+  drizzleOptions.contracts = contracts;
+} else {
+  const remoteContracts = downloadContractArtifactsSync();
+  console.log(remoteContracts);
+  drizzleOptions.contracts = remoteContracts;
+}
+
 export default drizzleOptions;
diff --git a/packages/concordia-app/src/utils/drizzleUtils.js b/packages/concordia-app/src/utils/drizzleUtils.js
new file mode 100755
index 0000000..613d0cd
--- /dev/null
+++ b/packages/concordia-app/src/utils/drizzleUtils.js
@@ -0,0 +1,47 @@
+// const downloadContractArtifacts = async () => {
+import { NUMBER_OF_CONTRACTS } from '../constants/contracts/ContractNames';
+
+export const downloadContractArtifacts = async () => {
+  const headers = new Headers();
+  headers.append('Access-Control-Allow-Origin', 'http://localhost:7000');
+  headers.append('Access-Control-Allow-Credentials', 'true');
+
+  const requestOptions = {
+    method: 'GET',
+    redirect: 'follow',
+    headers,
+  };
+
+  const remoteContracts = await fetch('http://127.0.0.1:8400/contracts/asdf', requestOptions)
+    .then((response) => response.text())
+    .then((contractsRawData) => JSON.parse(contractsRawData));
+
+  if (remoteContracts.length !== NUMBER_OF_CONTRACTS) {
+    throw new Error(`Version mismatch detected. Artifacts brought ${remoteContracts.length} contracts but app 
+    expected ${NUMBER_OF_CONTRACTS}`);
+  }
+
+  return remoteContracts;
+};
+
+export const downloadContractArtifactsSync = () => {
+  const xhrRequest = new XMLHttpRequest();
+  // xhrRequest.withCredentials = true;
+  xhrRequest.open('GET', 'http://127.0.0.1:8400/contracts/asdf', false);
+  xhrRequest.setRequestHeader('Access-Control-Allow-Origin', 'http://localhost:7000');
+  xhrRequest.setRequestHeader('Access-Control-Allow-Credentials', 'true');
+  xhrRequest.send(null);
+
+  if (xhrRequest.status === 200) {
+    const contractsRawData = xhrRequest.responseText;
+    const remoteContracts = JSON.parse(contractsRawData);
+
+    if (remoteContracts.length !== NUMBER_OF_CONTRACTS) {
+      throw new Error(`Version mismatch detected. Artifacts brought ${remoteContracts.length} contracts but app 
+    expected ${NUMBER_OF_CONTRACTS}`);
+    }
+
+    return remoteContracts;
+  }
+  throw new Error(`Remote contract artifacts download request failed!\n${xhrRequest.responseText}`);
+};
diff --git a/packages/concordia-contracts-provider/.eslintrc.js b/packages/concordia-contracts-provider/.eslintrc.js
new file mode 100755
index 0000000..7ca05eb
--- /dev/null
+++ b/packages/concordia-contracts-provider/.eslintrc.js
@@ -0,0 +1,60 @@
+module.exports = {
+  env: {
+    browser: true,
+    es6: true,
+    jest: true,
+  },
+  extends: [
+    'plugin:react/recommended',
+    'airbnb',
+  ],
+  globals: {
+    Atomics: 'readonly',
+    SharedArrayBuffer: 'readonly',
+  },
+  parser: 'babel-eslint',
+  parserOptions: {
+    ecmaFeatures: {
+      jsx: true,
+    },
+    ecmaVersion: 2018,
+    sourceType: 'module',
+  },
+  plugins: [
+    'react',
+    'react-hooks',
+  ],
+  rules: {
+    'react/jsx-props-no-spreading': 'off',
+    'import/extensions': 'off',
+    'react/jsx-indent': [
+      'error',
+      4,
+      {
+        checkAttributes: true,
+        indentLogicalExpressions: true,
+      },
+    ],
+    'react/require-default-props': 'off',
+    'react/prop-types': 'off',
+    'react-hooks/rules-of-hooks': 'error',
+    'react-hooks/exhaustive-deps': 'error',
+    'max-len': ['warn', { code: 120, tabWidth: 4 }],
+    'no-unused-vars': 'warn',
+    'no-console': 'warn',
+    'no-shadow': 'warn',
+    'no-multi-str': 'warn',
+    'jsx-a11y/label-has-associated-control': [2, {
+      labelAttributes: ['label'],
+      controlComponents: ['Input'],
+      depth: 3,
+    }],
+  },
+  settings: {
+    'import/resolver': {
+      node: {
+        extensions: ['.js', '.jsx'],
+      },
+    },
+  },
+};
diff --git a/packages/concordia-contracts-provider/.gitignore b/packages/concordia-contracts-provider/.gitignore
new file mode 100755
index 0000000..b1c784e
--- /dev/null
+++ b/packages/concordia-contracts-provider/.gitignore
@@ -0,0 +1,22 @@
+# Node
+/node_modules
+
+# IDE
+.DS_Store
+.idea
+
+# Build Directories
+/build
+/src/build
+
+# Logs
+/log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Misc
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
diff --git a/packages/concordia-contracts-provider/package.json b/packages/concordia-contracts-provider/package.json
new file mode 100755
index 0000000..7bdc166
--- /dev/null
+++ b/packages/concordia-contracts-provider/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "concordia-contracts-provider",
+  "description": "A server that provides built contracts for Concordia.",
+  "version": "0.1.0",
+  "private": true,
+  "main": "src/index.js",
+  "scripts": {
+    "start": "node -r esm src/index.js"
+  },
+  "license": "MIT",
+  "dependencies": {
+    "cors": "^2.8.5",
+    "esm": "~3.2.25",
+    "express": "^4.17.1",
+    "lodash": "^4.17.20",
+    "multer": "^1.4.2",
+    "multiparty": "^4.2.2"
+  },
+  "devDependencies": {
+    "eslint": "^7.19.0",
+    "eslint-config-airbnb": "^18.2.1",
+    "eslint-plugin-jsx-a11y": "^6.4.1",
+    "eslint-plugin-react": "^7.22.0",
+    "eslint-plugin-react-hooks": "^4.2.0"
+  }
+}
diff --git a/packages/concordia-contracts-provider/src/constants.js b/packages/concordia-contracts-provider/src/constants.js
new file mode 100755
index 0000000..e46b59b
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/constants.js
@@ -0,0 +1,3 @@
+export const API_HOST = '127.0.0.1';
+export const API_PORT = '8400';
+export const UPLOADED_CONTRACTS_DIR = './contracts-uploads/';
diff --git a/packages/concordia-contracts-provider/src/controllers/download.js b/packages/concordia-contracts-provider/src/controllers/download.js
new file mode 100755
index 0000000..5748fff
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/controllers/download.js
@@ -0,0 +1,19 @@
+import * as fs from 'fs';
+import path from 'path';
+import { UPLOADED_CONTRACTS_DIR } from '../constants';
+
+const downloadContracts = async (req, res) => {
+  const { params: { hash } } = req;
+  const directoryPath = path.join(`${__dirname}/../../${UPLOADED_CONTRACTS_DIR}/${hash}`);
+  const contracts = [];
+
+  fs.readdirSync(directoryPath).forEach((contractFilename) => {
+    const rawContractData = fs.readFileSync(path.join(`${directoryPath}/${contractFilename}`), 'utf-8');
+    const contractJson = JSON.parse(rawContractData);
+    contracts.push(contractJson);
+  });
+
+  res.send(contracts);
+};
+
+export default downloadContracts;
diff --git a/packages/concordia-contracts-provider/src/controllers/upload.js b/packages/concordia-contracts-provider/src/controllers/upload.js
new file mode 100755
index 0000000..018a047
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/controllers/upload.js
@@ -0,0 +1,19 @@
+import upload from '../middleware/upload';
+
+const uploadContracts = async (req, res) => {
+  try {
+    await upload(req, res);
+
+    if (req.files.length <= 0) {
+      return res.send('You must select at least 1 file.');
+    }
+
+    return res.send('Files have been uploaded.');
+  } catch (error) {
+    console.log(error);
+
+    return res.send(`Error when trying upload many files: ${error}`);
+  }
+};
+
+export default uploadContracts;
diff --git a/packages/concordia-contracts-provider/src/index.js b/packages/concordia-contracts-provider/src/index.js
new file mode 100755
index 0000000..462db85
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/index.js
@@ -0,0 +1,19 @@
+import express from 'express';
+import cors from 'cors';
+import initRoutes from './routes/web';
+import { API_HOST, API_PORT } from './constants';
+
+const app = express();
+
+const corsOptions = {
+  origin: ['localhost:7000', '127.0.0.1:7000', 'http://localhost:7000'],
+  optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
+};
+
+app.use(express.urlencoded({ extended: true }));
+app.use(cors(corsOptions));
+
+initRoutes(app);
+app.listen(API_PORT, () => {
+  console.log(`Contracts provider listening at http://${API_HOST}:${API_PORT}`);
+});
diff --git a/packages/concordia-contracts-provider/src/middleware/upload.js b/packages/concordia-contracts-provider/src/middleware/upload.js
new file mode 100755
index 0000000..ced18fa
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/middleware/upload.js
@@ -0,0 +1,32 @@
+import * as util from 'util';
+import * as path from 'path';
+import * as fs from 'fs';
+import multer from 'multer';
+import { UPLOADED_CONTRACTS_DIR } from '../constants';
+
+const storage = multer.diskStorage({
+  destination: (req, file, callback) => {
+    const { params: { hash } } = req;
+    const contractsPath = path.join(`${__dirname}/../../${UPLOADED_CONTRACTS_DIR}/${hash}`);
+
+    fs.mkdirSync(contractsPath, { recursive: true });
+    callback(null, contractsPath);
+    // callback(null, UPLOADED_CONTRACTS_DIR);
+  },
+  filename: (req, file, callback) => {
+    const match = ['application/json'];
+
+    if (match.indexOf(file.mimetype) === -1) {
+      const message = `<strong>${file.originalname}</strong> is invalid. Only JSON files are accepted.`;
+      return callback(message, null);
+    }
+
+    const filename = `${file.originalname}`;
+    callback(null, filename);
+  },
+});
+
+const uploadFiles = multer({ storage }).array('contracts');
+const uploadFilesMiddleware = util.promisify(uploadFiles);
+
+export default uploadFilesMiddleware;
diff --git a/packages/concordia-contracts-provider/src/routes/web.js b/packages/concordia-contracts-provider/src/routes/web.js
new file mode 100755
index 0000000..5bdd4fb
--- /dev/null
+++ b/packages/concordia-contracts-provider/src/routes/web.js
@@ -0,0 +1,14 @@
+import express from 'express';
+import downloadContracts from '../controllers/download';
+import uploadContracts from '../controllers/upload';
+
+const router = express.Router();
+
+const routes = (app) => {
+  router.get('/contracts/:hash', downloadContracts);
+  router.post('/contracts/:hash', uploadContracts);
+
+  return app.use('/', router);
+};
+
+export default routes;