diff --git a/Text/Css.hs b/Text/Css.hs
--- a/Text/Css.hs
+++ b/Text/Css.hs
@@ -24,7 +24,6 @@
 import Control.Arrow ((***), second)
 import Text.IndentToBrace (i2b)
 import Data.Functor.Identity (runIdentity)
-import Control.Monad (unless)
 
 #if MIN_VERSION_base(4,5,0)
 import Data.Monoid ((<>))
@@ -106,6 +105,7 @@
 data CDData url = CDPlain Builder
                 | CDUrl url
                 | CDUrlParam (url, [(Text, Text)])
+                | CDMixin Mixin
 
 pack :: String -> Text
 pack = T.pack
@@ -201,14 +201,14 @@
              -> Block Unresolved
              -> Either String (DList (Block Resolved))
 -- FIXME share code with blockToCss
-blockRuntime cd render' (Block x attrs z mixins) = do
-    unless (null mixins) $ Left "Runtime Lucius does not support mixins"
+blockRuntime cd render' (Block x attrs z mixinsDerefs) = do
+    mixins <- mapM getMixin mixinsDerefs
     x' <- mapM go' $ intercalate [ContentRaw ","] x
     attrs' <- mapM resolveAttr attrs
     z' <- mapM (subGo x) z -- FIXME use difflists again
     Right $ \rest -> Block
         { blockSelector = mconcat x'
-        , blockAttrs    = attrs'
+        , blockAttrs    = concat $ attrs' : map mixinAttrs mixins
         , blockBlocks   = ()
         , blockMixins   = ()
         } : foldr ($) rest z'
@@ -218,6 +218,12 @@
     -}
   where
     go' = contentToBuilderRT cd render'
+
+    getMixin d =
+        case lookup d cd of
+            Nothing -> Left $ "Mixin not found: " ++ show d
+            Just (CDMixin m) -> Right m
+            Just _ -> Left $ "For " ++ show d ++ ", expected Mixin"
 
     resolveAttr :: Attr Unresolved -> Either String (Attr Resolved)
     resolveAttr (Attr k v) = Attr <$> (mconcat <$> mapM go' k) <*> (mconcat <$> mapM go' v)
diff --git a/Text/Lucius.hs b/Text/Lucius.hs
--- a/Text/Lucius.hs
+++ b/Text/Lucius.hs
@@ -19,6 +19,9 @@
     , luciusRT
     , luciusRT'
     , luciusRTMinified
+      -- *** Mixin
+    , luciusRTMixin
+    , RTValue (..)
     , -- * Datatypes
       Css
     , CssUrl
@@ -61,6 +64,7 @@
 import Control.Monad (when, unless)
 import Data.Monoid (mconcat)
 import Data.List (isSuffixOf)
+import Control.Arrow (second)
 
 -- |
 --
@@ -285,12 +289,22 @@
 
 luciusRT' :: TL.Text
           -> Either String ([(Text, Text)] -> Either String [TopLevel Resolved])
-luciusRT' tl =
+luciusRT' =
+    either Left (Right . go) . luciusRTInternal
+  where
+    go :: ([(Text, RTValue)] -> Either String [TopLevel Resolved])
+       -> ([(Text, Text)] -> Either String [TopLevel Resolved])
+    go f = f . map (second RTVRaw)
+
+luciusRTInternal
+    :: TL.Text
+    -> Either String ([(Text, RTValue)] -> Either String [TopLevel Resolved])
+luciusRTInternal tl =
     case parse parseTopLevels (TL.unpack tl) (TL.unpack tl) of
         Left s -> Left $ show s
         Right tops -> Right $ \scope -> go scope tops
   where
-    go :: [(Text, Text)]
+    go :: [(Text, RTValue)]
        -> [TopLevel Unresolved]
        -> Either String [TopLevel Resolved]
     go _ [] = Right []
@@ -311,9 +325,9 @@
         bs' <- mapM (goBlock scope) bs
         rest' <- go scope rest
         Right $ TopAtBlock name (mconcat m) (concat bs') : rest'
-    go scope (TopVar k v:rest) = go ((pack k, pack v):scope) rest
+    go scope (TopVar k v:rest) = go ((pack k, RTVRaw $ pack v):scope) rest
 
-    goBlock :: [(Text, Text)]
+    goBlock :: [(Text, RTValue)]
             -> Block Unresolved
             -> Either String [Block Resolved]
     goBlock scope =
@@ -321,10 +335,33 @@
       where
         scope' = map goScope scope
 
-    goScope (k, v) = (DerefIdent (Ident $ unpack k), CDPlain $ fromText v)
+    goScope (k, rt) =
+        (DerefIdent (Ident $ unpack k), cd)
+      where
+        cd =
+            case rt of
+                RTVRaw t -> CDPlain $ fromText t
+                RTVMixin m -> CDMixin m
 
 luciusRT :: TL.Text -> [(Text, Text)] -> Either String TL.Text
 luciusRT tl scope = either Left (Right . renderCss . CssWhitespace) $ either Left ($ scope) (luciusRT' tl)
+
+-- | Runtime Lucius with mixin support.
+--
+-- Since 1.0.6
+luciusRTMixin :: TL.Text -- ^ template
+              -> Bool -- ^ minify?
+              -> [(Text, RTValue)] -- ^ scope
+              -> Either String TL.Text
+luciusRTMixin tl minify scope =
+    either Left (Right . renderCss . cw) $ either Left ($ scope) (luciusRTInternal tl)
+  where
+    cw
+        | minify = CssNoWhitespace
+        | otherwise = CssWhitespace
+
+data RTValue = RTVRaw Text
+             | RTVMixin Mixin
 
 -- | Same as 'luciusRT', but output has no added whitespace.
 --
diff --git a/shakespeare-css.cabal b/shakespeare-css.cabal
--- a/shakespeare-css.cabal
+++ b/shakespeare-css.cabal
@@ -1,5 +1,5 @@
 name:            shakespeare-css
-version:         1.0.5.1
+version:         1.0.6
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
diff --git a/test/ShakespeareCssTest.hs b/test/ShakespeareCssTest.hs
--- a/test/ShakespeareCssTest.hs
+++ b/test/ShakespeareCssTest.hs
@@ -429,6 +429,21 @@
                     }
                 |]
 
+    it "runtime mixin" $ do
+        let bins = [luciusMixin|
+                   bin:bin2;
+                   /* FIXME not currently implementing sublocks in mixins
+                   foo2 {
+                       x: y
+                   }
+                   */
+                   |] :: Mixin
+        -- No sublocks celper "foo{bar:baz;bin:bin2}foo foo2{x:y}" [lucius|
+        Right (T.pack "foo{bar:baz;bin:bin2}") @=? luciusRTMixin
+            (T.pack "foo { bar: baz; ^{bins} }")
+            True
+            [(TS.pack "bins", RTVMixin bins)]
+
     it "& subblocks" $
         celper "foo:bar{baz:bin}"
         [lucius|
