diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py
index dbd072d5..f99f3815 100644
--- a/bigchaindb/backend/localmongodb/query.py
+++ b/bigchaindb/backend/localmongodb/query.py
@@ -32,6 +32,24 @@ def get_transaction(conn, transaction_id):
         pass
 
 
+@register_query(LocalMongoDBConnection)
+def store_metadata(conn, metadata):
+    try:
+        return conn.run(
+            conn.collection('metadata')
+            .insert_many(metadata, ordered=False))
+    except DuplicateKeyError:
+        pass
+
+
+@register_query(LocalMongoDBConnection)
+def get_metadata(conn, transaction_ids):
+    return conn.run(
+        conn.collection('metadata')
+        .find({'id': {'$in': transaction_ids}},
+              projection={'_id': False}))
+
+
 @register_query(LocalMongoDBConnection)
 def store_asset(conn, asset):
     try:
diff --git a/bigchaindb/backend/localmongodb/schema.py b/bigchaindb/backend/localmongodb/schema.py
index e6c8e40e..2d916856 100644
--- a/bigchaindb/backend/localmongodb/schema.py
+++ b/bigchaindb/backend/localmongodb/schema.py
@@ -27,7 +27,7 @@ def create_database(conn, dbname):
 
 @register_schema(LocalMongoDBConnection)
 def create_tables(conn, dbname):
-    for table_name in ['transactions', 'assets', 'blocks']:
+    for table_name in ['transactions', 'assets', 'blocks', 'metadata']:
         logger.info('Create `%s` table.', table_name)
         # create the table
         # TODO: read and write concerns can be declared here
@@ -39,6 +39,7 @@ def create_indexes(conn, dbname):
     create_transactions_secondary_index(conn, dbname)
     create_assets_secondary_index(conn, dbname)
     create_blocks_secondary_index(conn, dbname)
+    create_metadata_secondary_index(conn, dbname)
 
 
 @register_schema(LocalMongoDBConnection)
@@ -86,3 +87,15 @@ def create_assets_secondary_index(conn, dbname):
 def create_blocks_secondary_index(conn, dbname):
     conn.conn[dbname]['blocks']\
         .create_index([('height', DESCENDING)], name='height')
+
+
+def create_metadata_secondary_index(conn, dbname):
+    logger.info('Create `assets` secondary index.')
+
+    # the id is the txid of the transaction where metadata was defined
+    conn.conn[dbname]['metadata'].create_index('id',
+                                               name='transaction_id',
+                                               unique=True)
+
+    # full text search index
+    conn.conn[dbname]['metadata'].create_index([('$**', TEXT)], name='text')
diff --git a/bigchaindb/backend/query.py b/bigchaindb/backend/query.py
index efbcfcd7..766d6668 100644
--- a/bigchaindb/backend/query.py
+++ b/bigchaindb/backend/query.py
@@ -33,6 +33,20 @@ def store_asset(connection, asset):
     raise NotImplementedError
 
 
+@singledispatch
+def store_metadata(connection, metadata):
+    """Write metadata to the metadata table.
+
+    Args:
+        metadata (dict): transaction metadata.
+
+    Returns:
+        The result of the operation.
+    """
+
+    raise NotImplementedError
+
+
 @singledispatch
 def store_transaction(connection, signed_transaction):
     """Same as write_transaction."""
@@ -331,11 +345,11 @@ def get_assets(connection, asset_ids):
 
 
 @singledispatch
-def get_metadata(connection, txn_ids):
+def get_metadata(connection, transaction_ids):
     """Get a list of metadata from the metadata table.
 
     Args:
-        txn_ids (list): a list of ids for the metadata to be retrieved from
+        transaction_ids (list): a list of ids for the metadata to be retrieved from
         the database.
 
     Returns:
diff --git a/bigchaindb/tendermint/lib.py b/bigchaindb/tendermint/lib.py
index 67f899e4..37fb9d6e 100644
--- a/bigchaindb/tendermint/lib.py
+++ b/bigchaindb/tendermint/lib.py
@@ -51,11 +51,18 @@ class BigchainDB(Bigchain):
             if asset['data']:
                 backend.query.store_asset(self.connection, asset)
 
+        metadata = transaction.pop('metadata')
+        transaction_metadata = {'id': transaction['id'],
+                                'metadata': metadata}
+
+        backend.query.store_metadata(self.connection, [transaction_metadata])
+
         return backend.query.store_transaction(self.connection, transaction)
 
     def get_transaction(self, transaction_id, include_status=False):
         transaction = backend.query.get_transaction(self.connection, transaction_id)
         asset = backend.query.get_asset(self.connection, transaction_id)
+        metadata = backend.query.get_metadata(self.connection, [transaction_id])
 
         if transaction:
             if asset:
@@ -63,6 +70,13 @@ class BigchainDB(Bigchain):
             else:
                 transaction['asset'] = {'data': None}
 
+            if 'metadata' not in transaction:
+                metadata = metadata[0] if metadata else None
+                if metadata:
+                    metadata = metadata.get('metadata')
+
+                transaction.update({'metadata': metadata})
+
             transaction = Transaction.from_dict(transaction)
 
         if include_status:
diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py
index ad89848f..67643fff 100644
--- a/tests/backend/localmongodb/test_queries.py
+++ b/tests/backend/localmongodb/test_queries.py
@@ -77,6 +77,49 @@ def test_text_search():
     test_text_search('assets')
 
 
+def test_write_metadata():
+    from bigchaindb.backend import connect, query
+    conn = connect()
+
+    metadata = [
+        {'id': 1, 'data': '1'},
+        {'id': 2, 'data': '2'},
+        {'id': 3, 'data': '3'}
+    ]
+
+    # write the assets
+    query.store_metadata(conn, deepcopy(metadata))
+
+    # check that 3 assets were written to the database
+    cursor = conn.db.metadata.find({}, projection={'_id': False})\
+                             .sort('id', pymongo.ASCENDING)
+
+    assert cursor.count() == 3
+    assert list(cursor) == metadata
+
+
+def test_get_metadata():
+    from bigchaindb.backend import connect, query
+    conn = connect()
+
+    metadata = [
+        {'id': 1, 'metadata': None},
+        {'id': 2, 'metadata': {'key': 'value'}},
+        {'id': 3, 'metadata': '3'},
+    ]
+
+    conn.db.metadata.insert_many(deepcopy(metadata), ordered=False)
+
+    for meta in metadata:
+        assert query.get_metadata(conn, [meta['id']])
+
+
+def test_text_metadata():
+    from ..mongodb.test_queries import test_text_search
+
+    test_text_search('metadata')
+
+
 def test_get_owned_ids(signed_create_tx, user_pk):
     from bigchaindb.backend import connect, query
     conn = connect()
diff --git a/tests/web/test_metadata.py b/tests/web/test_metadata.py
index 22c025ae..68efacc7 100644
--- a/tests/web/test_metadata.py
+++ b/tests/web/test_metadata.py
@@ -3,6 +3,7 @@ import pytest
 METADATA_ENDPOINT = '/api/v1/metadata/'
 
 
+@pytest.mark.tendermint
 def test_get_metadata_with_empty_text_search(client):
     res = client.get(METADATA_ENDPOINT + '?search=')
     assert res.json == {'status': 400,
@@ -10,6 +11,7 @@ def test_get_metadata_with_empty_text_search(client):
     assert res.status_code == 400
 
 
+@pytest.mark.tendermint
 def test_get_metadata_with_missing_text_search(client):
     res = client.get(METADATA_ENDPOINT)
     assert res.status_code == 400
@@ -85,3 +87,64 @@ def test_get_metadata_limit(client, b):
         res = client.get(METADATA_ENDPOINT + '?search=meta&limit=1')
         assert res.status_code == 200
         assert len(res.json) == 1
+
+
+@pytest.mark.bdb
+@pytest.mark.tendermint
+def test_get_metadata_tendermint(client, tb):
+    from bigchaindb.models import Transaction
+
+    b = tb
+
+    # test returns empty list when no assets are found
+    res = client.get(METADATA_ENDPOINT + '?search=abc')
+    assert res.json == []
+    assert res.status_code == 200
+
+    # create asset
+    asset = {'msg': 'abc'}
+    metadata = {'key': 'my_meta'}
+    tx = Transaction.create([b.me], [([b.me], 1)], metadata=metadata,
+                            asset=asset).sign([b.me_private])
+
+    b.store_transaction(tx)
+
+    # test that metadata is returned
+    res = client.get(METADATA_ENDPOINT + '?search=my_meta')
+    assert res.status_code == 200
+    assert len(res.json) == 1
+    assert res.json[0] == {
+        'metadata': {'key': 'my_meta'},
+        'id': tx.id
+    }
+
+
+@pytest.mark.bdb
+@pytest.mark.tendermint
+def test_get_metadata_limit_tendermint(client, tb):
+    from bigchaindb.models import Transaction
+
+    b = tb
+
+    # create two assets
+    asset1 = {'msg': 'abc 1'}
+    meta1 = {'key': 'meta 1'}
+    tx1 = Transaction.create([b.me], [([b.me], 1)], metadata=meta1,
+                             asset=asset1).sign([b.me_private])
+    b.store_transaction(tx1)
+
+    asset2 = {'msg': 'abc 2'}
+    meta2 = {'key': 'meta 2'}
+    tx2 = Transaction.create([b.me], [([b.me], 1)], metadata=meta2,
+                             asset=asset2).sign([b.me_private])
+    b.store_transaction(tx2)
+
+    # test that both assets are returned without limit
+    res = client.get(METADATA_ENDPOINT + '?search=meta')
+    assert res.status_code == 200
+    assert len(res.json) == 2
+
+    # test that only one asset is returned when using limit=1
+    res = client.get(METADATA_ENDPOINT + '?search=meta&limit=1')
+    assert res.status_code == 200
+    assert len(res.json) == 1