                {:stage stage :mode mode :config config}))
       after)))
 
+(defn deep-merge [a b]
+  (cond
+    (and (map? a) (map? b))
+    (merge-with deep-merge a b)
+
+    (and (vector? a) (vector? b))
+    (->> (concat a b)
+         (distinct)
+         (into []))
+
+    (string? b)
+    b
+
+    (number? b)
+    b
+
+    (boolean? b)
+    b
+
+    :else
+    (throw (ex-info "failed to merge config value" {:a a :b b}))
+    ))
+
 (defn config-merge [config mode]
-  ;; FIXME: merge nested maps, vectors
-  (let [mode-opts
-        (get config mode)]
-    (merge config mode-opts)))
+  (let [mode-opts (get config mode)]
+    (-> config
+        (deep-merge mode-opts)
+        (dissoc :release :dev))))
 
 (defn get-target-fn [target]
 

(defn init
  ([mode config]
   (init (cljs/init-state) mode config))
  ([init-state mode {:keys [id target compiler-options] :as config}]
   {:pre [(cljs/compiler-state? init-state)
          (map? config)
          (keyword? mode)

          (some? target)]
    :post [(cljs/compiler-state? %)]}

   (let [{:keys [compiler-options] :as config}
         (config-merge config mode)

         target-fn
