diff --git a/SUMMARY.md b/SUMMARY.md
index 3efaac7..9b8f840 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -12,5 +12,6 @@
- [PLAN-0001: GraphQL Query Prefetching](./engineering-plans/0001-graphql-query-prefetching.md)
- [PLAN-0002: Ethereum Tracing Cache](./engineering-plans/0002-ethereum-tracing-cache.md)
- [PLAN-0003: Remove JSONB Storage](./engineering-plans/0003-remove-jsonb-storage.md)
+ - [PLAN-0004: Subgraph Schema Merging](./engineering-plans/0004-subgraph-schema-merging.md)
- [Obsolete Plans](./engineering-plans/obsolete.md)
- [Rejected Plans](./engineering-plans/rejected.md)
diff --git a/engineering-plans/0004-subgraph-schema-merging.md b/engineering-plans/0004-subgraph-schema-merging.md
new file mode 100644
index 0000000..72ac979
--- /dev/null
+++ b/engineering-plans/0004-subgraph-schema-merging.md
@@ -0,0 +1,284 @@
+# PLAN-0004: Subgraph Schema Merging
+
+
+ - Author
+ - Jorge Olivero
+
+ - Implements
+ - RFC-0001 Subgraph Composition
+
+ - Engineering Plan pull request
+ - Engineering Plan PR
+
+ - Obsoletes (if applicable)
+ - -
+
+ - Date of submission
+ - 2019-12-09
+
+ - Date of approval
+ - TBD
+
+ - Approved by
+ - TBD
+
+
+## Summary
+
+Subgraph composition allows a subgraph to import types from another subgraph. Imports are designed to be loosely coupled throughout the deployment and indexing phases, and tightly coupled during query execution for the subgraph.
+
+To generate an API schema for the subgraph, the subgraph schema needs to be merged with the imported subgraph schemas. The merging process needs to take the following into account:
+
+1. An imported schema not being available on the Graph Node
+2. An imported schema mising a type imported by the subgraph schema
+3. A schema imported by subgraph name changes
+4. Ability to tell which subgraph/schema each type belongs to
+
+## Implementation
+
+The schema merging implementation consists of two parts:
+
+1. A cache of subgraph schemas
+2. The schema merging logic
+
+### Schema Merging
+
+Add a `merged_schema(&Schema, HashMap) -> Schema` function to the `graphql::schema` crate which will add each of the imported types to the provided document with a `@subgraphId` directive denoting which subgraph the type came from. If any of the imported types have non scalar fields, import those types as well.
+
+The `HashMap` includes all of the schemas in the subgraph's import graph which are available on the Graph Node. For each `@import` directive on the subgraph, find the imported types by tracing their path along the import graph.
+
+- If any schema node along that path is missing or if a type is missing in the schema, add a type definition to the subgraphs merged schema with the proper name, a `@subgraphId(id: "...")` directive (if available), and a `@placeholder` directive denoting that type was not found.
+sc- If the type is found, copy it and add a `@subgraphId(id: "...")` directive.
+- If the type is imported with the `{ name: "", as: "" }` format, the merged type will include an `@originalName(name: "...")` directive preserving the type name from the original schema.
+
+The `api_schema` function will add all the necessary types and fields for the imported types without requiring any changes.
+
+#### Example #1: Complete merge
+
+Local schema before calling `merged_schema`:
+
+```graphql
+type _Schema_
+ @import(
+ types: ["B"],
+ from: { id: "X" }
+ )
+
+type A @entity {
+ id: ID!
+ foo: B!
+}
+```
+
+Imported Schema X:
+
+```graphql
+type B @entity {
+ id: ID!
+ bar: String
+}
+```
+
+Schema after calling `merged_schema`:
+
+```graphql
+type A @entity {
+ id: ID!
+ foo: B!
+}
+
+type B @entity @subgraphId(id: "X") {
+ id: ID!
+ bar: String
+}
+```
+
+#### Example #2: Incomplete merge
+
+Schema before calling `merged_schema`:
+
+```graphql
+type _Schema_
+ @import(
+ types: ["B"],
+ from: { id: "X" }
+ )
+
+type A @entity {
+ id: ID!
+ foo: B!
+}
+```
+
+Imported Schema X:
+
+```graphql
+NOT AVAILABLE
+```
+
+Schema after calling `merged_schema`
+
+```graphql
+type A @entity @subgraphId(id: "...") {
+ id: ID!
+ foo: B!
+}
+
+type B @entity @placeholder {
+ id: ID!
+}
+```
+
+#### Example #3: Complete merge with `{ name: "...", as: "..." }`
+
+Schema before calling `merged_schema`
+
+```graphql
+type _Schema_
+ @imports(
+ types: [{ name: "B", as: "BB" }]
+ from: { id: "X" }
+ )
+
+type B @entity {
+ id: ID!
+ foo: BB!
+}
+```
+
+Imported Schema X:
+
+```graphql
+type B @entity {
+ id: ID!
+ bar: String
+}
+```
+
+Schema after calling `merged_schema`
+
+```graphql
+type B @entity {
+ id: ID!
+ foo: BB!
+}
+
+type BB @entity @subgraphId(id: "X") @originalName(name: "B") {
+ id: ID!
+ bar: String
+}
+```
+
+#### Example #4: Complete merge with nested types
+
+Schema before calling `merged_schema`
+
+```graphql
+type _Schema_
+ @imports(
+ types: [{ name: "B", as: "BB" }]
+ from: { id: "X" }
+ )
+
+type B @entity {
+ id: ID!
+ foo: BB!
+}
+```
+
+Imported Schema X:
+
+```graphql
+type _Schema_
+ @imports(
+ types: [{ name: "C", as: "CC" }]
+ from: { id: "Y" }
+ )
+
+type B @entity {
+ id: ID!
+ bar: CC!
+ baz: DD!
+}
+
+type DD @entity {
+ id: ID!
+}
+```
+
+Imported Schema Y:
+
+```graphql
+type C @entity {
+ id: ID!
+}
+```
+
+Schema after calling `merged_schema`
+
+```graphql
+type B @entity {
+ id: ID!
+ foo: BB!
+}
+
+type BB @entity @subgraphId(id: "X") @originalName(name: "B") {
+ id: ID!
+ bar: CC!
+ baz: DD!
+}
+
+type CC @entity @subgraphId(id: "Y") @originalName(name: "C") {
+ id: ID!
+}
+
+type DD @entity @subgraphId(id: "X") {
+ id: ID!
+}
+```
+
+
+
+After the schema document is merged, the `api_schema` function will be called.
+
+### Cache Invalidation
+
+For each schema in the cache, keep a vector of subgraph pointers containing an element for each schema in the subgraph's import graph which was imported by name and the subgraph ID which was used during the schema merge. When a schema is accessed from the schema cache (and possibly only if this check hasn't happened in the last N seconds), check the current version for each of these schemas and run a diff against the versions used for the most recent schema merge. If there are any new versions, re merge the schema.
+
+Currently the `schema_cache` in the `Store` is a `Mutex>`. A `SchemaPair` consists of two fields: `input_schema` and `api_schema`. To support the refresh flow, `SchemaPair` would be extended to be a `SchemaEntry`, with the fields `input_schema`, `api_schema`, `schemas_imported` (`Vec<(SchemaReference, SubgraphDeploymentId)>`), and a `last_refresh_check` timestamp.
+
+A more performant invalidation solution would be to have the cache maintain a listener notifying it every time a subgraph's current version changes. Upon receiving the notification the listener scans the schemas in the cache for those which should be remerged.
+
+
+## Tests
+
+1. Schemas are merged correctly when all schemas and imported types are available.
+
+2. Placeholder types are properly inserted into the merged schema when a schema is not available.
+
+3. Placeholder types are properly inserted into the merged schema when the relevant schemas are available but the types are not.
+
+4. The cache is invalidated when the store returns an updated version of a cache entry's dependency.
+
+## Migration
+
+Subgraph composition is an additive feature which doesn't require a special migration plan.
+
+## Documentation
+
+Documentation on https://thegraph.com/docs needs to outline:
+
+1. The reserved _Schema_ type and how to define imports on it.
+2. The semantics of importing by subgraph ID vs. subgraph name, i.e. what happens when a subgraph imported by name removes expected types from the schema.
+3. How queries are processed when imported subgraphs schemas or types are not available on the graph-node processing the query.
+
+## Implementation Plan
+
+- Implement the `merged_schema` function (2d)
+- Write tests for the `merged_schema` function (1d)
+- Integrate `merged_schema` into `Store::cached_schema` and update the cache to include the relevant information for imported schemas and types (1d)
+- Add cache invalidation logic to `Store::cached_schema` (2d)
+
+## Open Questions
+
+- The execution of queries and subscriptions needs to be updated to leverage the types in a merged schema.
diff --git a/engineering-plans/0005-subgraph-composition-query-execution.md b/engineering-plans/0005-subgraph-composition-query-execution.md
new file mode 100644
index 0000000..351949f
--- /dev/null
+++ b/engineering-plans/0005-subgraph-composition-query-execution.md
@@ -0,0 +1,121 @@
+# PLAN-0005: Subgraph Composition Query Execution
+
+
+ - Author
+ - Jorge Olivero
+
+ - Implements
+ - RFC-0001 Subgraph Composition
+
+ - Engineering Plan pull request
+ - Engineering Plan PR
+
+ - Obsoletes (if applicable)
+ - -
+
+ - Date of submission
+ - 2020-1-14
+
+ - Date of approval
+ - TBD
+
+ - Approved by
+ - TBD
+
+
+## Summary
+
+Since subgraph composition allows a subgraph to import types from another subgraph, GraphQL query execution will need to traverse a subgraph's import graph to resolve concrete types.
+Because imported schemas/types are loosely coupled, query execution also needs to address missing types in the api schema during resolution.
+In addition, imported types which have been renamed need to be mapped back to their original name so that queries can resolve correctly.
+Lastly, to simplify query execution graph-node needs to deny subgraphs with JSONB storage from using subgraph composition.
+
+## Implementation
+
+1. Support Custom Type Names: Ensure @originalName directives on the imported types are used to query the correct sql tables.
+2. Codify New Query Runtime Errors: Ensure @placeholder types are acknowledged and proper errors are returned during query execution when a type's subgraph is not deployed to the graph-node resolving the query.
+3. Query Correct Subgraph: Ensure that @subgraphId directives on imported types are used correctly in all cases.
+4. Add Subgraph Composition Feature Flag: Ensure subgraphs JSONB storage can not use subgraph composition.
+
+### Support Custom Type Names
+
+When a type is imported with the name/as syntax:
+
+```graphql
+type _Schema_ @import(types: [{ name: "A", as: "B" }], from: { id: "..." })
+```
+
+an `@originalName` directive is added to it when it is merged into the target schema:
+
+```graphql
+type B @entity @subgraphId(id: "...") @originalName(name: "A") {
+ id: ID!
+ ...
+}
+```
+
+GraphQL query resolution needs to make use of the `@originalName` directive to ensure SQL queries are made against the correct tables.
+
+The follow code locations need to be updated:
+
+1. https://github.com/graphprotocol/graph-node/blob/master/graphql/src/store/resolver.rs#L362-L379f
+
+2. https://github.com/graphprotocol/graph-node/blob/master/graphql/src/store/query.rs#L21-L27
+
+### Codify New Query Runtime Errors
+
+When a type is imported from a schema that is unavailable a placeholder is created to ensure the schema remains complete:
+
+```graphql
+type _Schema_ @import(types: [{ name: "A", as: "B" }], from: { id: "..." })
+```
+
+when the subgraph with `id: "..."` is unavailable during the merge a placeholder will be created:
+
+```graphql
+type B @entity @placeholder @originalName(name: "A") {
+ id: ID!
+}
+```
+
+Since the `@subgraphId` won't be available for this type during query execution, we have to handle this as query runtime error in the follow locations:
+
+1. https://github.com/graphprotocol/graph-node/blob/master/graphql/src/store/resolver.rs#L359
+
+### Query Correct Subgraph
+
+Imported types in a merged schema which are available on the Graph Node executing the query will have `@subgraphId` and `@originalName` directives actings as pointers to the relevant database table.
+Ensure that the changes introduced in https://github.com/graphprotocol/graph-node/pull/1483 work seamlessly with the merged schema.
+
+### Add Subgraph Composition Feature Flag
+
+Do not allow subgraph composition for subgraphs which use the JSONB storage engine.
+
+## Tests
+
+### Unit Tests:
+
+### Integration Tests:
+
+1. Querying an A || [A] with an imported field B || [B] with an imported field C || [C]
+
+## Migration
+
+Subgraph composition is an additive feature and does not require a migration plan.
+
+## Documentation
+
+Document the following aspects of query execution along side more general subgraph composition documentation:
+
+1. New runtime errors which could occur during query execution
+
+## Implementation Plan
+
+- Support custom type names (1d)
+- Codify new query execution runtime errors (1d)
+- Add subgraph composition feature flag (1d)
+- Ensure correct subgraph is queried during single object resolution and prefetch paths (3d)
+
+## Open Questions
+
+1. Is any work needed to ensure subgraph composition is not leveraged by a subgraph using the JSONB storage engine?
diff --git a/engineering-plans/approved.md b/engineering-plans/approved.md
index 8c1f549..0298de2 100644
--- a/engineering-plans/approved.md
+++ b/engineering-plans/approved.md
@@ -3,3 +3,4 @@
- [PLAN-0001: GraphQL Query Prefetching](./0001-graphql-query-prefetching.md)
- [PLAN-0002: Ethereum Tracing Cache](./0002-ethereum-tracing-cache.md)
- [PLAN-0003: Remove JSONB Storage](./0003-remove-jsonb-storage.md)
+- [PLAN-0004: Subgraph Schema Merging](./0004-subgraph-schema-merging.md)